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

[SFPHP] PHP 5.NEW: The Best Bits

[SFPHP] PHP 5.NEW: The Best Bits

Are you still stuck on PHP 5.2? Looking to migrate from 5.3 to the latest and greatest?

This talk will cover all the best new features and tooling since PHP 5.3, all the way up to PHP 5.6 and beyond.

Namespaces, Closures, Traits, Generators, Variadics/Argument unpacking, Composer, PSR-0 autoloading and more!

Davey Shafik

August 04, 2014
Tweet

More Decks by Davey Shafik

Other Decks in Programming

Transcript

  1. Proprietary and Confidential •Community Engineer at Engine Yard •Author of

    Zend PHP 5 Certification Study Guide, Sitepoints PHP Anthology: 101 Essential Tips, Tricks & Hacks & PHP Master: Write Cutting Edge Code •A contributor to Zend Framework 1 & 2, phpdoc, & PHP internals • Original creator of PHAR/ PHP_Archive • Lead for PHPWomen US •@dshafik Davey Shafik
  2. Proprietary and Confidential • Extensions:! • ereg deprecated! • SPL

    always enabled! • Reflection always enabled! • NOWDOC! • Goto! • stream_context_set_default()! • Magic Methods:! • __invoke() • __callStatic() • __call() now called on protected/private method access! • Performance Increase! PHP 5.3 5.3
  3. Proprietary and Confidential • 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! • UTF-8 by default (instead of iso-8859-1)! • Array callbacks — $foo = [$obj, ‘method’]; $foo = [“Class”, “method”]; then: $foo(); ! • Callable typehint, accepts function names, array callbacks, closures, classes with __invoke() magic method! • Better Memory Usage and Performance ! • (even better than PHP 5.3) PHP 5.4 5.4
  4. Proprietary and Confidential • PCRE /e Modifier deprecated! • ext/mysql

    now officially deprecated! • boolval() to complement intval(), floatval()/doubleval(), strval(). Same as (bool) $var; • JsonSerializable interface! • Fully-qualified Class name constant: ClassName::CLASS! • empty() now supports any valid expression! • set_(error|exception)_handler() to NULL to return to default behavior PHP 5.5 5.5
  5. Proprietary and Confidential • T_POW: ** Exponent operator, raise left

    operand to the power of right! • Constant Scalar Expressions! • __debugInfo() magic method — intercept var_dump() • GMP operator overloading (engine level only !) PHP 5.6 5.6
  6. Proprietary and Confidential • Avoid Naming Collisions! • Alias Long

    Names! • Must be defined at the top! • Relative Namespaces are Supported! • Import/Alias with "use" keyword! • Can namespace classes, functions, and constants (using const) Namespaces <?php namespace Zend\Http\Client\Adapter; class Socket implements HttpAdapter, StreamInterface { } ?> 5.3
  7. Proprietary and Confidential • Remove leading namespace separator! • Replace

    namespace separator with directory separator! • Replace underscores with directory separator! • Add .php to the end PSR-0 5.3
  8. Proprietary and Confidential Install dependencies (from composer.lock)! $ composer install

    ! Update dependencies & write composer.lock! $ composer update Composer 5.3
  9. Proprietary and Confidential <?php require 'vendor/autoload.php'; ! use Zend\Http\Client\Adapter\Socket as

    HttpClient; $client = new HttpClient; 
 // Automagically (lazy) loaded ! Optimize the Autoloader with a classmap: $ composer install --optimize-autoloader $ composer update --optimize-autoloader Autoloading 5.3
  10. Proprietary and Confidential • Prior to PHP 5.6:! • Outside

    of the namespace, function names/constants had to be fully qualified! • You could alias the namespace to shorten it (ugh!)! ! • Add two new keyword sequences:! • use function \foo\bar\function! • use const \foo\bar\BAZ! • Use commas to import multiples Import Namespaced Functions & Constants 5.6
  11. Proprietary and Confidential Import Namespaced Functions & Constants namespace foo\bar

    { const HELLO_WORLD = "Hello World"; function strlen($str) { return \strlen($str); } } namespace { use function foo\bar\strlen; use function foo\bar\non_existent; // Doesn't exist! use const foo\bar\HELLO_WORLD; var_dump(strlen(HELLO_WORLD)); // not ambiguous var_dump(non_existent()); // Does not fall-through // to global scope: fatal error } 5.6
  12. Proprietary and Confidential Great for DSLs! Import Namespaced Functions &

    Constants use function html\div, html\p, html\em; $html = div(p('Some', em('Text'))); 5.6
  13. Proprietary and Confidential Closures <?php $a = array(3, 2, 5,

    6, 1); usort($a, function ($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; }); ?> 5.3
  14. Proprietary and Confidential • Explicitly passed in via the use

    construct Inheriting Scope $who = "World"; $sayHello = function() use ($who) { echo "Hello $who"; }; $sayHello(); 5.3
  15. Proprietary and Confidential • $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() $this in closures 5.4
  16. Proprietary and Confidential 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 } } 5.4
  17. Proprietary and Confidential • 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. Rebinding $this 5.4
  18. Proprietary and Confidential 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(); 5.4
  19. Proprietary and Confidential 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 5.4
  20. Proprietary and Confidential Array Dereferencing function returnArray() { return ['a'

    => 'b', 'c' => 'd']; } $foo = returnArray()['a']; // b 5.4 5.5 Literal Dereferencing ["one", "two", "three"][0]; // "one" "foo"[0]; // f
  21. Proprietary and Confidential • Compiler-level copy and paste (almost literally!)!

    • New Keywords: trait, use, as and insteadof • Can use multiple traits! – as and insteadof resolve conflicts! • Can define methods, abstract methods, and properties! • Can be namespaced, identified just like classes/functions/constants Traits 5.4
  22. Proprietary and Confidential namespace Ds\Util; trait SecureDebugInfo { public function

    __debugInfo() { $info = (array) $this; foreach ($info as $key => $value) { // Hide elements starting with '_' if ($key[0] == '_') { unset($info[$key]); } } } } Defining a Trait 5.4
  23. Proprietary and Confidential • Uses the “use” keyword! • Use

    multiple traits like namespaces, separate use calls, or comma- separated. Using a Trait namespace!Ds;! class!MyClass!{! ! use!Util\SecureDebugInfo;! } 5.4
  24. Proprietary and Confidential trait One { public function one() {

    } } trait Two { public function two() { } } trait Three { use One, Two; // Trait three now comprises of 
 // all three traits. public function Three() { } } Inheriting In Traits 5.4
  25. Proprietary and Confidential class Numbers { use One; // Adds

    One->one() public function two() { } public function three() { } } class MoreNumbers extends Numbers { use Two; // Two->two() overrides Numbers->two() public function one() { } // Overrides Numbers->one() } (Trait One->one) class EvenMoreNumbers extends MoreNumbers { use Three; // Three->one() overrides MoreNumbers->one() // Three->two() overrides MoreNumbers->two() 
 // (Trait Two->two) // Three->three() overrides inherited 
 Numbers->three() public function three() { } // Overrides Three->three() } Inheritance & Traits 5.4
  26. Proprietary and Confidential namespace Ds\Util; trait SecureDebugInfo { public function

    __debugInfo() { return $this->getData(); } abstract public function getData(); } Trait Requirements 5.4
  27. Proprietary and Confidential Fatal error: Trait method <name> has not

    been applied, because there are collisions with other trait methods on <class> ! class MyClass { use Ds\Util\SecureDebugInfo, 
 My\Framework\DebugHelper { Ds\Util\SecureDebugInfo::__debugInfo insteadof My\Framework\DebugHelper; } } Conflict Resolution 5.4
  28. Proprietary and Confidential class MyClass { use Ds\Util\SecureDebugInfo, My\Framework\DebugHelper {

    Ds\Util\SecureDebugInfo::__debugInfo insteadof My\Framework\DebugHelper; My\Framework\DebugHelper::__debugInfo as debugHelperInfo; } } Aliases 5.4
  29. Proprietary and Confidential class MyClass { use MyTrait { MyTrait::myMethod

    as protected; MyTrait::myOtherMethod as private AliasName; } } Changing Visibility 5.4
  30. Proprietary and Confidential class Numbers { use One, Two; }

    var_dump(class_uses('Numbers')); Output: array(2) { ["One"]=> string(3) "One" ["Two"]=> string(3) "Two" } ! Using Array Dereferencing: if (class_uses('MyClass')['SomeTrait']) { ! //"MyClass"uses"the"SomeTrait! } Detecting Traits 5.4
  31. Proprietary and Confidential Binary Numbers $var = 0b01; // Binary

    (base 2) In Addition To: $var = 1234; // Integer $var = -123; // Signed Integer (+/-) $var = 1.23; // Float $var = 0123; // Octal (base 8) $var = 0x1A; // Hexadecimal (base 16) 5.4
  32. Proprietary and Confidential Short 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']; 5.4
  33. Proprietary and Confidential Dynamic Method Calls // Variable static methods

    ! $var = "staticMethod"; ClassName::{$var}(); ! // Instantiation Time Access (new ClassName)->instanceMethod();
 
 // UGLY. $var = "instanceMethod"; (new ClassName)->{$var}(); 5.4
  34. Proprietary and Confidential •Allows assignment of nested array values (1st

    level) to multiple variables, within the foreach declaration list() support in foreach $result = [ [ 'name' => 'Davey Shafik', 'email' => '[email protected]', ], [ 'name' => 'Helgi Þormar Þorbjörnsson', 'email' => '[email protected]', ] ]; foreach ($result as list($name, $email)) { echo $name, ': ', $email . PHP_EOL; } 5.5
  35. Proprietary and Confidential •Easy access to the fully qualified class

    name via a simple constant. Allows for easy dynamic creation of class (think: Reflection, Unit Testing) Fully Qualified Classname Constant namespace App { class Config { } $className = "Config"; new $className; // Fatal error: Class 'Config' not found // Instead: $className = "App\Config"; new $className; // Works // Added in 5.5: $className = Config::class; // = App\Config new $className; } 5.5
  36. Proprietary and Confidential • Code within a finally block is

    always run after either of the try, or catch blocks.! • Remember: Catch is optional “finally” keyword try { // Try something } catch (\Exception $exception) { // Handle exception } finally { // Whatever happened, do this } 5.5
  37. Proprietary and Confidential •Makes password hashing super easy •Purpose: to

    make sure everyone uses safe password storage •Uses the excellent bcrypt (currently) •Salting is automatic, but can be supplied •The hash itself identifies the algorithm, salt and options options when passed to password_verify() •You may pass an array with salt and cost as third argument to password_hash() Simple Password Hashing 5.5
  38. Proprietary and Confidential Simple Password Hashing (cont.) $options = [

    'cost' => 20, 'salt' => 'bcryptuses22characters' ]; $hash = password_hash("testing", PASSWORD_DEFAULT, $options); $hash = password_hash("testing", PASSWORD_DEFAULT); if (password_verify("testing", $hash)) { // valid } Specify Options: 5.5
  39. Proprietary and Confidential •Also provides two helper functions: – password_needs_rehash()

    will determine if the hash uses the current algorithm, cost and salt, returning true if it doesn’t match. – password_get_info() returns an array providing information about a hash such as algorithm, cost and salt. Simple Password Hashing (cont.) 5.5
  40. Proprietary and Confidential •A strong salt makes a dictionary attack

    much more difficult •A high cost means it takes a long time (say, 1/10th second) to generate a single password, making brute force attacks too slow to be effective •The cost is what makes SHA-1 and MD5 poor options because they are designed to be fast, this is the enemy of security. •Additionally, MD5 suffers from too many easy collisions (e.g. two different strings that create the same hash) More on password security Goal: Make both dictionary and brute force attacks difficult. 5.5
  41. Proprietary and Confidential Hashing Rates Algorithm Hashes/ second MD5 SHA-1

    SHA-512 bcrypt MD5 180 Billion/ second 65% Faster 99.9997% Faster 99.9999996% Faster SHA-1 63 Billion/ second 185% Slower 99.9994% Faster 99.999887% Faster SHA-512 364,000/ second 49.5M% Slower 17.3M% Slower 80.49% Faster bcrypt 71,000/ second 253.5M% Slower 88.7M% Slower 412% Slower Data Source: http://passwords12.at.ifi.uio.no/Jeremi_Gosney_Password_Cracking_HPC_Passwords12.pdf 5.5
  42. Proprietary and Confidential •Introduces new yield keyword - execution is

    handed back to the iterating mechanism (e.g. foreach) and then continues from, the yield •Functions and methods are automatically return generators when yield is found within them •Generators are just simple ways to implement iterators; without having to duplicate a bunch of boilerplate code •Technically implemented using the Generator class, similar to the magic Closure class. Generators 5.5
  43. Proprietary and Confidential Anatomy of Generator Flow function helloGenerator($who) {

    // First iteration starts here $greeting = ["Hello", "Hi", "Hola", "Bonjour"][rand(0, 3)]; yield $greeting; // Control passed back to foreach // Next iteration starts here yield " "; // Control passed back to foreach // Third iteration starts here yield ucfirst($who) . "!\n"; // Control passed back to foreach } $generator = helloGenerator("world"); // No code is executed yet foreach ($generator as $value) { echo $value; } Output: $RandomGreeting World!\n 5.5
  44. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function MyGenerator()

    { // First iteration starts here for ($i = 0; $i < 5; $i++) { yield $i; // Control passed back to foreach // Second iteration starts here // The for iteration completes, and goes to the next loop } } 0: 0 1: 5 2: 10 3: 15 4: 20 Output 5.5
  45. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  46. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  47. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  48. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  49. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  50. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  51. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  52. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  53. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  54. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  55. Proprietary and Confidential Anatomy of Generator Flow (Cont.) function gen()

    { echo "One"; yield "Two"; echo "Three"; yield "Four"; echo "Five"; } $generator = gen(); ! $generator->rewind(); if ($generator->valid()) { echo $generator->current(); } $generator->next(); 5.5
  56. Proprietary and Confidential •A return; (note: a return with a

    value is a parse error) •An exception is thrown (and not caught within the generator) •There are no more yields Anatomy of Generator Flow (Cont.) Generators will return true for valid() until: 5.5
  57. Proprietary and Confidential •You can send any data into a

    generator •It is used as an expression, rather than a statement •This also advances the generator •You can send and receive at the “same time” Sending data into a Generator function logger($fileName) { $fileHandle = fopen($fileName, 'a'); while (true) { fwrite($fileHandle, yield . PHP_EOL); } } $logger = logger(__DIR__ . '/log'); $logger->send('Foo'); $logger->send('Bar'); 5.5
  58. Proprietary and Confidential •My first implementation for the next slide

    didn’t work how I expected! •Neither did the 2nd, 3rd or 4th... •In fact, I thought I found a bug •Then I created a test case, and things started to make sense ! •I still don’t think there’s any reasonable use-case for this functionality! Confession Time 5.5
  59. Proprietary and Confidential Test Case function!gen()!{! !!!!$i!=!0;! !!!!while!(true)!{! !!!!!!!!file_put_contents("./log",!! !!!!!!!!!!!!myDate()!.'!'.!

    !!!!!!!!!!!!(yield3$i++)!.!'!'!.! !!!!!!!!!!!!PHP_EOL! !!!!!!!!,!FILE_APPEND);! !!!!}! }! !! function!myDate()!{! !!!!return!date("YOmOd!H:i:s");! }! !! $gen!=!gen();! var_dump($gen:>send("First!Call"));!//"1! sleep(3);! var_dump($gen:>send("Second!Call"));!//"2 Log File 2013-02-04 03:39:51 First Call 2013-02-04 03:39:51 Second Call 5.5
  60. Proprietary and Confidential •Sends an exception into the Generator •Throws

    the exception at the yield •The actual yielded value isn’t returned Sending Exceptions into Generators 5.5
  61. Proprietary and Confidential Sending Exceptions into Generators function gen() {

    echo "Foo\n"; try { while (true) { yield "bat"; } } catch (Exception $e) { echo "Exception: {$e->getMessage()}\n"; } echo "Bar\n"; } $gen = gen(); var_dump($gen->current()); // echos "Foo" and dumps string (3) "bat" $gen->throw(new Exception('Test')); // echos "Exception: Test" and "Bar" var_dump($gen->valid()); // dumps bool(false)
 5.5
  62. Proprietary and Confidential • Variadic means to accept a variable

    number of arguments! • Previously you needed to use func_num_args()/func_get_args()! • Which includes defined arguments also!! • New syntax: "… $variable" (triple dot)! • Array with just the variable arguments! • Self-documenting code! • Supports by-reference! • Allows type hints! • Must be the last argument! Variadic Functions 5.6
  63. Proprietary and Confidential Variadic Functions function fn($reqParam, $optParam = null,

    ...$params) { var_dump($reqParam, $optParam, $params); } fn(1); // 1, null, [] fn(1, 2); // 1, 2, [] fn(1, 2, 3); // 1, 2, [3] fn(1, 2, 3, 4); // 1, 2, [3, 4] fn(1, 2, 3, 4, 5); // 1, 2, [3, 4, 5] 5.6
  64. Proprietary and Confidential Variadic Functions — References class MySQL implements

    DB { public function prepare($query, &...$params) { $stmt = $this->pdo->prepare($query); foreach ($params as $i => &$param) { $stmt->bindParam($i + 1, $param); } return $stmt; } // ... } $stmt = $db->prepare('INSERT INTO users 
 (name, email, age) VALUES (?, ?, ?)', $name, $email, $age);
 foreach ($usersToInsert as list($name, $email, $age)) { $stmt->execute(); } 5.6
  65. Proprietary and Confidential Variadic Functions — Type hints function hooks($name,

    Callable ... $callbacks) { foreach ($callbacks as $callback) { $callback(); } } 5.6
  66. Proprietary and Confidential • The opposite of variadics, unpack an

    array (or similar) as arguments! • No more call_user_func_array() (which is “slow”)! • Valid for any argument list (including new foo(… $var))! • Must be at the end of the argument list! • Use it multiple times! Splat 5.6
  67. Proprietary and Confidential Splat function test(...$args) { var_dump($args); } test(1,

    2, 3); // [1, 2, 3] test(...[1, 2, 3]); // [1, 2, 3] test(...new ArrayIterator([1, 2, 3])); // [1, 2, 3] 5.6
  68. Proprietary and Confidential Splat $args1 = [1, 2, 3]; $args2

    = [4, 5, 6]; test(...$args1, ...$args2); // [1, 2, 3, 4, 5, 6] test(1, 2, 3, ...$args2); // [1, 2, 3, 4, 5, 6]
 test(...$args1, 4, 5, 6); // [1, 2, 3, 4, 5, 6] 5.6
  69. Proprietary and Confidential • Use expressions when defining:! • global

    constants with const keyword! • class constants with the const keyword! • class properties! • static variables! • function arguments Constant Scalar Expressions 5.6
  70. Proprietary and Confidential • ! 123 - Integers! • !

    123.456 - Floats! • ! “foo” - Strings! • ! __LINE__ - Line magic constant! • ! __FILE__ - File magic constant! • ! __DIR__ - Directory magic constant! • ! __TRAIT__ - Trait magic constant! • ! __METHOD__ - Method magic constant! • ! __FUNCTION__ - Function magic constant! • ! __NAMESPACE__ - Namespace magic constant! • ! <<<HEREDOC - HEREDOC string syntax (without variables)! • ! <<<'NOWDOC' - NOWDOC string syntax! • ! SOME_RANDOM_CONSTANT - Constants! Expression Suppport 5.6
  71. Proprietary and Confidential Global constants with const keyword const FOO

    = 1 + 1; const BAR = 1 << 1; const GREETING = "HELLO"; const BAZ = GREETING." WORLD!" 5.6
  72. Proprietary and Confidential Class constants with the const keyword class

    Foo { const FOO = 1 + 1; const BAR = 1 << 1; const GREETING = "HELLO"; const BAZ = self::GREETING." WORLD!" } 5.6
  73. Proprietary and Confidential Class Properties class Foo { const BAZ

    = 10; } class Bar { public $foo = 1 + 1; public $bar = [ 1 + 1, 1 << 2, Foo::BAZ => "foo "."bar" ]; public $baseDir = __DIR__ . "/base"; } 5.6
  74. Proprietary and Confidential Static Variables const BAR = 0x10; function

    foo() { static $a = 1 + 1; static $b = [1 << 2]; static $c = 0x01 | BAR; } 5.6
  75. Proprietary and Confidential Magic method to control the output of

    var_dump() __debugInfo() class File { // "Resource(stream)" isn't all that useful private $fp; // But all the stream meta data is public function __debugInfo() { return $this->fp ? stream_get_meta_data($fp) : []; } public function open($filename, $mode = 'r'){ $this->fp = fopen($filename, $mode); } } 5.6
  76. Proprietary and Confidential __debugInfo() (Cont.) $f = new File; var_dump($f);

    // object(File)#1 { } $f->open('http://php.net'); var_dump($f); /* object(File)#1 { ["wrapper_type"]=> string(4) "http" ["stream_type"]=> string(10) "tcp_socket" etc... */ 5.6