Slide 1

Slide 1 text

PHP 5.4: The New Bits 1

Slide 2

Slide 2 text

•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

Slide 3

Slide 3 text

One More Thing 3

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

About These Slides 5

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

The Small Stuff 7

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

More on SessionHandlerInterface 9

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Language Changes 11

Slide 12

Slide 12 text

Short Echo Tags 12

Slide 13

Slide 13 text

Short Echo Tags No longer depends on short_open_tags 13

Slide 14

Slide 14 text

Binary Numbers 14

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

New Array Syntax 16

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Array Dereferencing 18

Slide 19

Slide 19 text

Array Dereferencing function returnArray() { return ['a' => 'b', 'c' => 'd']; } $foo = returnArray()['a']; // b 19

Slide 20

Slide 20 text

Dynamic Method Calls 20

Slide 21

Slide 21 text

Dynamic Method Calls // Variable static methods $var = "staticMethod"; ClassName::{$var}(); // Instantiation Time Access (new ClassName)->instanceMethod(); // UGLY. $var = "instanceMethod"; (new ClassName)->{$var}(); 21

Slide 22

Slide 22 text

Improvements to Closures & Callbacks 22

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

$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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Rebinding $this Or: How to break the object model! 27

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Output Hello Fatal error: Call to private method bar::world() from context 'foo' 30

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Traits AKA Horizontal Re-use 32

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Trait Detection 41

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

Built-in CLI Server 44

Slide 45

Slide 45 text

Built in CLI Server • Use -S : (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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Thank You! • Feedback: • @dshafik • dshafi[email protected] • Slides: • http://daveyshafik.com/slides 52