Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[PHPUK] PHP 5.4: The New Bits

Fee39f0c0ffb29d9ac21607ed188be6b?s=47 Davey Shafik
February 24, 2012

[PHPUK] PHP 5.4: The New Bits

PHP 5.4 is about to be unleashed into the world; bringing some of the most exciting changes to the PHP language to date. Learn about traits, array dereferencing, indirect method calls using array callback syntax and improvements to closures and streams.

Fee39f0c0ffb29d9ac21607ed188be6b?s=128

Davey Shafik

February 24, 2012
Tweet

Transcript

  1. PHP 5.4: The New Bits 1

  2. •Engineer at Engine Yard for Orchestra.io PHP Platform as a

    Service (PaaS) •Author of Zend PHP 5 Certification Study Guide, Sitepoints PHP Anthology: 101 Essential Tips, Tricks & Hacks & PHP Master: Write Cutting Edge Code •A long time contributor to PEAR, phpdoc; new contributor to internals, CKEditor •Original Contributor to Zend Framework •@dshafik •(Buy My Books!) Davey Shafik 2
  3. One More Thing 3

  4. Hard of hearing: PLEASE SPEAK UP! (Everybody Forgets This!) 4

  5. About These Slides 5

  6. About These Slides • Two slides per “slide” • Title

    Slide (for when I’m talking) • Details slide (for later) • Nobody likes it when you can read the slide just as well as the speaker can • I like slides that are useful 6
  7. The Small Stuff 7

  8. The Small Stuff • SessionHandlerInterface added, used with session_set_save_handler() •

    PHP_BINARY constant gives the path to the... PHP binary • Notice now shown on array-to-string conversions • Better Memory Usage and Performance 8
  9. More on SessionHandlerInterface 9

  10. interface SessionHandlerInterface { public function open($sessionid); public function close(); public

    function read($sessionid); public function write($sessiondata); public function destroy($sessionid); public function gc($maxlifetime); } // Corresponds to: session_set_save_handler( $open, $close, $read, $write, $destroy, gc ); // Implemented by new internal class: class SessionHandler { } 10
  11. Language Changes 11

  12. Short Echo Tags 12

  13. Short Echo Tags <?="Now I Will Always Work!";?> No longer

    depends on short_open_tags 13
  14. Binary Numbers 14

  15. Binary Numbers $var = 0b01; // Binary (base 2) $var

    = 1234; // Integer $var = -123; // Signed Integer (+/-) $var = 1.23; // Float $var = 0123; // Octal (base 8) $var = 0x1A; // Hexadecimal (base 16) In Addition To: 15
  16. New Array Syntax 16

  17. New Array Syntax // Old $array = array(1, 2, 3);

    // New $array = [1, 2, 3]; // Old $a = array('a' => 'b', 'c' => 'd'); // New $a = ['a' => 'b', 'c' => 'd']; 17
  18. Array Dereferencing 18

  19. Array Dereferencing function returnArray() { return ['a' => 'b', 'c'

    => 'd']; } $foo = returnArray()['a']; // b 19
  20. Dynamic Method Calls 20

  21. Dynamic Method Calls // Variable static methods $var = "staticMethod";

    ClassName::{$var}(); // Instantiation Time Access (new ClassName)->instanceMethod(); // UGLY. $var = "instanceMethod"; (new ClassName)->{$var}(); 21
  22. Improvements to Closures & Callbacks 22

  23. Closures & Callbacks • New callable type hint (closures, function

    names, arrays, __invoke()) • $this now accessible inside closures (based on creation location) • Array callbacks for variable function calls • Change $this and/or scope with Closure::bind() and Closure- >bindTo() 23
  24. Callable Type hint function invokeCallback(callable $var) { $var(); } invokeCallback(function()

    { }); invokeCallback("functionName"); invokeCallback(['class', 'staticMethod']); invokeCallback([$object, 'method']); class Foo { public function __invoke() { } } invokeCallback(new Foo()); 24
  25. $this in closures class foo { public function getClosure() {

    return function() { return $this; } } } class bar { public function __construct() { $foo = new foo(); $func = $foo->getClosure(); $obj = $func(); // PHP 5.3: $obj == null // PHP 5.4: $obj == foo, not bar } } 25
  26. Array Callbacks class ClassName { public static function staticMethod() {

    var_dump(__METHOD__); } public function instanceMethod() { var_dump(__METHOD__); } } $callback = ['ClassName', 'staticMethod']; $callback(); // ClassName::staticMethod $callback = [new ClassName(), 'instanceMethod']; $callback(); // ClassName::instanceMethod 26
  27. Rebinding $this Or: How to break the object model! 27

  28. Rebinding $this • Doesn’t change the original closure — creates

    a duplicate • $this can be any object • $this and scope are separate — $this can be a different class to the access scope. 28
  29. Rebinding $this class foo { public function getClosure() { return

    function() { echo $this->hello; $this->world(); }; } } class bar { public $hello = "Hello "; private function world() { echo "World"; } } $foo = new Foo(); $closure = $foo->getClosure(); $bar = new Bar(); $newClosure = $closure->bindTo($bar); $newClosure(); 29
  30. Output Hello Fatal error: Call to private method bar::world() from

    context 'foo' 30
  31. Rebinding $this class foo { public function getClosure() { return

    function() { echo $this->hello; $this->world(); }; } } class bar { public $hello = "Hello "; private function world() { echo "World"; } } $foo = new Foo(); $closure = $foo->getClosure(); $bar = new Bar(); $newClosure = $closure->bindTo($bar); $newClosure = $closure->bindTo($bar, $bar); $newClosure(); // Hello World 31
  32. Traits AKA Horizontal Re-use 32

  33. Traits • Compiler-level copy and paste (literally!) • New Keywords:

    trait, use, as and insteadof • Can use multiple traits • as and insteadof resolve conflicts • Can define methods, abstract methods, and properties 33
  34. Traits trait sayHello { public function hello() { echo "Hello

    "; } } trait sayWorld { public function world() { echo "World"; } } class sayHelloWorld { use sayHello, sayWorld; } $say = new sayHelloWorld(); $say->hello(); // Hello $say->world(); // World 34
  35. Inheritance/Scope trait getHello { public function hello() { return "Hello";

    } } trait getWorld { public function world() { return "World"; } } trait sayHelloWorld { use getHello, getWorld; public function helloWorld() { echo $this->hello(), " ", $this->world(); } } class Greeting { use sayHelloWorld; } (new Greeting)->helloWorld(); // Hello World 35
  36. Precedence class say { public function sayHello() { echo 'Hello

    '; } } trait sayWorld { public function sayHello() { parent::sayHello(); // parent is unknown echo 'World'; } } class HelloWorld extends say { use sayWorld; // parent == say } class HiMum extends HelloWorld { public function sayHello() { parent::sayHello(); // parent == HelloWorld == sayWorld echo ", Hi mum!", PHP_EOL; } } (new HelloWorld)->sayHello(); echo PHP_EOL; // Hello World (new HiMum)->sayHello(); // Hello World, Hi mum! 36
  37. Method Visibility trait sayHello { public function hello() { echo

    "Hello "; } } trait sayWorld { private function world() { echo "World"; } } class sayHelloWorld { use sayHello, sayWorld { world as public; } } $say = new sayHelloWorld(); $say->hello(); // Hello $say->world(); // World 37
  38. Method Aliases trait sayHello { public function hello() { echo

    "Hello "; } } trait sayWorld { private function world() { echo "World"; } } class sayHelloWorld { use sayHello, sayWorld { hello as greeting; world as public planet; } } $say = new sayHelloWorld(); $say->greeting(); // Hello $say->planet(); // World 38
  39. Conflicts trait hello_en { public function greet() { echo "Hello

    "; } } trait mother_en_US { public function mother() { echo "Mom"; } } trait mother_en_UK { public function mother() { echo "Mum"; } } class HiMother { use hello_en, mother_en_US, mother_en_UK; public function sayHi($locale = 'UK') { $this->greet(); ($locale != 'US') ? $this->mother() : $this->mom(); } } (new HiMother)->sayHi('UK'); (new HiMother)->sayHi('US'); Fatal error: Trait method mother has not been applied, because there are collisions with other trait methods on HiMother on line 28 39
  40. Conflict Resolution trait hello_en { public function greet() { echo

    "Hello "; } } trait mother_en_US { public function mother() { echo "Mom"; } } trait mother_en_UK { public function mother() { echo "Mum"; } } class HiMother { use hello_en, mother_en_US, mother_en_UK { mother_en_UK::mother insteadof mother_en_US; mother_en_US::mother as mom; } public function sayHi($locale = 'UK') { $this->greet(); ($locale != 'US') ? $this->mother() : $this->mom(); } } (new HiMother)->sayHi('UK'); // Hello Mum (new HiMother)->sayHi('US'); // Hello Mom 40
  41. Trait Detection 41

  42. Trait Detection • instanceof doesn’t work because it’s literally engine-level

    copy and paste • class_uses() returns an array • Both keys and values are the trait names • We can use array dereferencing (another PHP 5.4 feature) to check! 42
  43. Trait Detection trait HelloWorld { public function hi() { echo

    "Hello World", PHP_EOL; } } class greeting { use HelloWorld; } $greeting = new greeting(); // This doesn’t work if ($greeting instanceof HelloWorld) { echo "instanceof: ", $greeting->hi(); } // This does - using array dereferencing! if (isset(class_uses($greeting)['HelloWorld'])) { echo "class_uses: ", $greeting->hi(); } 43
  44. Built-in CLI Server 44

  45. Built in CLI Server • Use -S <host>:<port> (capital S)

    flag to initiate • Document Root: Current working directory • Default file: index.php • Serves static assets (e.g. images, js, css) • Allows URL routing with simple PHP script 45
  46. Running the CLI Server davey@maat ~ $ /usr/local/php5/bin/php -S localhost:8080

    PHP 5.4.0RC6 Development Server started at Sun Jan 29 22:15:32 2012 Listening on localhost:8080 Document root is /Users/davey Press Ctrl-C to quit. [Sun Jan 29 22:15:36 2012] 127.0.0.1:49956 [200]: / [Sun Jan 29 22:15:37 2012] 127.0.0.1:49957 [404]: / favicon.ico - No such file or directory 46
  47. Output: /index.php array (size=21) 'DOCUMENT_ROOT' => string '/Users/davey' (length=12) 'REMOTE_ADDR'

    => string '127.0.0.1' (length=9) 'REMOTE_PORT' => string '49956' (length=5) 'SERVER_SOFTWARE' => string 'PHP 5.4.0RC6 Development Server' (length=31) 'SERVER_PROTOCOL' => string 'HTTP/1.1' (length=8) 'SERVER_NAME' => string 'localhost' (length=9) 'SERVER_PORT' => string '8080' (length=4) 'REQUEST_URI' => string '/' (length=1) 'REQUEST_METHOD' => string 'GET' (length=3) 'SCRIPT_NAME' => string '/index.php' (length=10) 'SCRIPT_FILENAME' => string '/Users/davey/index.php' (length=22) 'PHP_SELF' => string '/index.php' (length=10) 'HTTP_HOST' => string 'localhost:8080' (length=14) 'HTTP_CONNECTION' => string 'keep-alive' (length=10) 'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/ 535.7' (length=116) 'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/ xml;q=0.9,*/*;q=0.8' (length=63) 'HTTP_ACCEPT_ENCODING' => string 'gzip,deflate,sdch' (length=17) 'HTTP_ACCEPT_LANGUAGE' => string 'en-US,en;q=0.8' (length=14) 'HTTP_ACCEPT_CHARSET' => string 'ISO-8859-1,utf-8;q=0.7,*;q=0.3' (length=30) 'REQUEST_TIME_FLOAT' => float 1327893336.7823 'REQUEST_TIME' => int 1327893336 47
  48. Using a Router davey@maat ~ $ /usr/local/php5/bin/php -S localhost:8080 router.php

    PHP 5.4.0RC6 Development Server started at Sun Jan 29 22:15:32 2012 Listening on localhost:8080 Document root is /Users/davey Press Ctrl-C to quit. [Sun Jan 29 22:15:36 2012] 127.0.0.1:49956 [200]: / [Sun Jan 29 22:15:41 2012] 127.0.0.1:49956 [200]: /index.php Note: custom routed URLs do not show here (might be a bug!) 48
  49. Using a Router if (realpath(__DIR__ . "/.{$_SERVER['REQUEST_URI']}")) { // file

    exists, serve it — will execute PHP return false; } else { // route the request (could be ZF, li3, etc) MyRouter::route($_SERVER['REQUEST_URI']); } class MyRouter { static public function route($path) { echo "Requested Resource: $path"; } } // Check if we’re using the cli-server if (PHP_SAPI == 'cli-server') { ... } Example Router 49
  50. Output: /index.php array (size=21) 'DOCUMENT_ROOT' => string '/Users/davey' (length=12) 'REMOTE_ADDR'

    => string '127.0.0.1' (length=9) 'REMOTE_PORT' => string '49956' (length=5) 'SERVER_SOFTWARE' => string 'PHP 5.4.0RC6 Development Server' (length=31) 'SERVER_PROTOCOL' => string 'HTTP/1.1' (length=8) 'SERVER_NAME' => string 'localhost' (length=9) 'SERVER_PORT' => string '8080' (length=4) 'REQUEST_URI' => string '/' (length=1) 'REQUEST_METHOD' => string 'GET' (length=3) 'SCRIPT_NAME' => string '/index.php' (length=10) 'SCRIPT_FILENAME' => string '/Users/davey/index.php' (length=22) 'PHP_SELF' => string '/index.php' (length=10) 'HTTP_HOST' => string 'localhost:8080' (length=14) 'HTTP_CONNECTION' => string 'keep-alive' (length=10) 'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7' (length=116) 'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/ xml;q=0.9,*/*;q=0.8' (length=63) 'HTTP_ACCEPT_ENCODING' => string 'gzip,deflate,sdch' (length=17) 'HTTP_ACCEPT_LANGUAGE' => string 'en-US,en;q=0.8' (length=14) 'HTTP_ACCEPT_CHARSET' => string 'ISO-8859-1,utf-8;q=0.7,*;q=0.3' (length=30) 'REQUEST_TIME_FLOAT' => float 1327893336.7823 'REQUEST_TIME' => int 1327893336 50
  51. Output: /foo/bar Requested Resource: /foo/bar array (size=23) 'DOCUMENT_ROOT' => string

    '/Users/davey/Dropbox/Talks/2012/PHP 5.4 - The New Bits/ cli-server' (length=65) 'REMOTE_ADDR' => string '::1' (length=3) 'REMOTE_PORT' => string '52584' (length=5) 'SERVER_SOFTWARE' => string 'PHP 5.4.0RC6 Development Server' (length=31) 'SERVER_PROTOCOL' => string 'HTTP/1.1' (length=8) 'SERVER_NAME' => string 'localhost' (length=9) 'SERVER_PORT' => string '8080' (length=4) 'REQUEST_URI' => string '/foo/bar' (length=8) 'REQUEST_METHOD' => string 'GET' (length=3) 'SCRIPT_NAME' => string '/index.php' (length=10) 'SCRIPT_FILENAME' => string '/Users/davey/Dropbox/Talks/2012/PHP 5.4 - The New Bits/cli-server/index.php' (length=75) 'PATH_INFO' => string '/foo/bar' (length=8) 'PHP_SELF' => string '/index.php/foo/bar' (length=18) 'HTTP_HOST' => string 'localhost:8080' (length=14) 'HTTP_CONNECTION' => string 'keep-alive' (length=10) 'HTTP_CACHE_CONTROL' => string 'max-age=0' (length=9) 'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7' (length=116) 'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/xml;q=0.9,*/ *;q=0.8' (length=63) 'HTTP_ACCEPT_ENCODING' => string 'gzip,deflate,sdch' (length=17) 'HTTP_ACCEPT_LANGUAGE' => string 'en-US,en;q=0.8' (length=14) 'HTTP_ACCEPT_CHARSET' => string 'ISO-8859-1,utf-8;q=0.7,*;q=0.3' (length=30) 'REQUEST_TIME_FLOAT' => float 1327903577.3323 'REQUEST_TIME' => int 1327903577 51
  52. Thank You! • Feedback: • @dshafik • dshafik@engineyard.com • Slides:

    • http://daveyshafik.com/slides 52