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

[DutchPHP Conference 2015] What To Expect When You're Expecting: PHP 7

[DutchPHP Conference 2015] What To Expect When You're Expecting: PHP 7

PHP 7 is coming, and with it will come new features, backwards compatibility breaks, and huge performance gains.

This talk will get you prepared for all the changes in this upcoming release and offer practical advice you can implement now to ensure you code still works come upgrade time.

Davey Shafik

June 27, 2015
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 •@dshafik Davey Shafik
  2. Mar 15
 2015 Jun 15
 2015 Oct 15 2015 Feature

    Freeze Finalize Implementation Release Candidates PHP 7.0 Final Alphas/Betas (we are here)
  3. • ASP Tags: <%, <%= and %> • Script Tags:

    <script language="php"></script> Alternative PHP Tags
  4. • All mysql_* functions removed • Use mysqli_* for direct

    migration • Use mysqli OO or PDO instead ext/mysql
  5. switch ($expr) { default: echo "Hello World"; break; default: //

    only this one would execute echo "Goodbye Moon!"; break; } Fatal error: Switch statements may only contain one default clause Multiple Default Cases in Switch
  6. Performance (benchmark.php) 0 3,000,000,000 6,000,000,000 9,000,000,000 12,000,000,000 20.01.2014 18.02.2014 21.02.2014

    28.02.2014 07.03.2014 14.03.2014 21.03.2014 28.03.2014 04.04.2014 11.04.2014 18.04.2014 25.04.2014 05.05.2014 18.05.2014 26.05.2014 03.06.2014 09.06.2014 30.06.2014 09.07.2014 14.07.2014 15.08.2014 02.09.2014 07.10.2014 21.11.2014 31.12.2014 19.03.2015 30.04.2015 Time (sec) Operations 0.777 0.837 1.159 1.201 1.219 1.302 1.35 1.407 1.367 1.412 1.497 1.492 1.432 1.49 1.414 1.492 1.515 1.559 1.571 1.821 1.941 1.941 1.906 1.941 1.83 1.898 2.115 2.115 1.898 1.83 1.941 1.906 1.941 1.941 1.821 1.571 1.559 1.515 1.492 1.414 1.49 1.432 1.492 1.497 1.412 1.367 1.407 1.35 1.302 1.219 1.201 1.159 0.837 0.777
  7. Performance (Wordpress Homepage) 0 2,500,000,000 5,000,000,000 7,500,000,000 10,000,000,000 20.01.2014 04.04.2014

    11.04.2014 18.04.2014 25.04.2014 05.05.2014 18.05.2014 26.05.2014 03.06.2014 09.06.2014 30.06.2014 09.07.2014 14.07.2014 15.08.2014 02.09.2014 07.10.2014 21.11.2014 31.12.2014 19.03.2015 30.04.2015 Time (sec) Operations (Wordpress) 11.081 11.756 12.629 13.43 13.89 14.15 14.864 14.81 15.85 15.94 16.54 17.403 18.245 18.913 18.957 20.857 21.503 22.592 23.676 26.756 26.756 23.676 22.592 21.503 20.857 18.957 18.913 18.245 17.403 16.54 15.94 15.85 14.81 14.864 14.15 13.89 13.43 12.629 11.756 11.081
  8. 59%

  9. • Mostly Invisible to Userland • Paves the way for

    more performance (optimizing is easier with an AST) • Allows for easier implementation of future features AST — Abstract Syntax Tree
  10. • Variable-Variables are the problem! • PHP 7 will read

    left-to-right consistently! • Easy to be forwards compatible with the addition of braces and parenthesis • Lots of new dereferencing options available like nested :: and array- derefenced closures. Uniform Variable Syntax
  11. Proprietary and Confidential Uniform Variable Syntax: Consistency Changes Syntax Old

    Interpretation New Interpretation $$var['key1']['key2'] ${$var['key1']['key2']} ($$var)['key1']['key2'] $var->$prop['key'] $var->{$prop['key']} ($var->$prop)['key'] $var->$prop['key']() $var->{$prop['key']}() ($var->$prop)['key']() Class::$var['key']() Class::{$var['key']}() (Class::$var)['key']()
  12. Proprietary and Confidential (...)['foo'] (...)->foo (...)->foo() (...)::$foo (...)::foo() (...)() Arbitrary

    Expression Dereferencing Including: (function() { ... })() ($obj->closure)()
  13. Proprietary and Confidential "string"->toLower() • Allows for future object-scalars
 [$obj,

    'method']() • Allows array-method callables 'Foo'::$bar • ¯\_()_/¯ Dereferencing Scalars
  14. Proprietary and Confidential global $$foo->bar; // instead use: global ${$foo->bar};

    (or better yet: don’t use globals!) No Longer Supported
  15. • Behavior of assert() expanded in PHP 7 • Can

    be turned off, to remove overhead in production • Can emit exceptions on failure, defaults to a WARNING • Allow for a custom message Assertions
  16. Proprietary and Confidential assert("false === true"); 
 // Not evaluated

    if zend.assertions = 0
 Warning: assert(): Assertion "false === true" failed assert("false === true", "Expression was falsey"); 
 // Supply a custom error message Warning: assert(): Expression was falsey: "false === true" failed Assertions
  17. • When calling a method on a non-object it is

    now a catchable fatal error. • This means you can continue execution if the error is handled. Catchable Fatal Error: Call to member function on non-object
  18. set_error_handler(function($code, $message) { var_dump($code, $message); }); $var = null; $var->method();


    // Fatal Error: Call to a member function method() on null echo "Hello World"; // Still runs Catchable Fatal Error: Call to member function on non-object
  19. Engine Exceptions: Call to member function on non-object try {

    $var = null; $var->method(); } catch (\Error $e) { echo $e->getMessage(); 
 // Call to a member function method() on null } echo "Hello World"; // Still runs
  20. • Can be handled gracefully • Finally blocks are called

    • Destructors are called • Easier Catchable fatal error handling Engine Exceptions
  21. Proprietary and Confidential \Throwable interface ├── \Exception implements \Throwable └──

    \Error implements \Throwable ├── \TypeError extends \Error ├── \ParseError extends \Error └── \AssertionError extends \Error Exception Hierarchy
  22. Proprietary and Confidential •Engine exceptions do not extend \Exception so

    that old catch- all’s will not catch them, preserving BC •New \Throwable interface from which \Error and \Exception implement •catch (\Throwable) { } is the new catch-all. •Cannot be implemented in userland — you must extend \Error or \Exception still •\Throwable can itself be extended and implemented \Throwable
  23. • Now throws \Error exceptions instead of Catchable/Fatal errors •

    No BC break for Fatal (uncaught exception == actually Fatal) • Small BC break for Catchable: no longer possible to suppress errors entirely in set_error_handler() (must catch the exception) \Error
  24. • Thrown when a parse error is encountered in an

    include/ require or eval() \ParseError try { include "parse-error.php"; } catch (\ParseError $e) { var_dump($e); } // parse-error.php function $foo() { }
  25. Proprietary and Confidential \ParseError object(ParseError)#1 (7) { ["message":protected]=> string(84) "syntax

    error, 
 unexpected '$foo' (T_VARIABLE), expecting identifier 
 (T_STRING) or '('" ["string":"Error":private]=> string(0) "" ["code":protected]=> int(4) ["file":protected]=> string(21) "/root/parse-error.php" ["line":protected]=> int(2) ["trace":"Error":private]=> array(0) {} ["previous":"Error":private]=> NULL }
  26. • Throws \TypeError on type mis-matches in strict mode \TypeError

    function compare(Comparable $a, Comparable $b) { return $a <=> $b; } try { echo compare($obj, $obj2); } catch (\TypeError $e) { var_dump($e); }
  27. Proprietary and Confidential object(TypeError)#1 (7) { ["message":protected]=> string(110) "Argument 1

    passed to compare() must 
 be of the type Comparable, int given" ["string":"Error":private]=> string(0) "" ["code":protected]=> int(1) ["file":protected]=> string(20) "/root/type-error.php" ["line":protected]=> int(3) ["trace":"Error":private]=> array(1) { [0]=> array(4) { ["file"]=> string(20) "/root/type-error.php" ["line"]=> int(8) ["function"]=> string(3) "compare" ["args"]=> array(2) { [0]=> … [1]=> … } } \TypeError
  28. • Throws \AssertionError on assert() failures \AssertionError ini_set('zend.assertions', 1); ini_set('assert.exception',

    1); try { assert("false === true", "Expression was falsey"); } catch (\AssertionError $e) { var_dump($e); }
  29. Proprietary and Confidential object(AssertionError)#1 (7) { ["message":protected]=> string(21) "Expression was

    falsey" ["string":"Error":private]=> string(0) "" ["code":protected]=> int(1) ["file":protected]=> string(22) "/root/assert-error.php" ["line":protected]=> int(6) ["trace":"Error":private]=> array(1) { [0]=> array(4) { ["file"]=> string(22) "/root/assert-error.php" ["line"]=> int(6) ["function"]=> string(6) "assert" ["args"]=> array(2) { [0]=> string(14) "false === true" [1]=> string(21) "Expression was falsey" \TypeError
  30. \o/

  31. • First trinary return operator: • Returns -1 if left

    operand is less than right • Returns 0 if left and right operands are identical • Returns +1 if left operand is greater than right • Originally proposed by me! • Thankfully championed by Andrea Faulds and finally Stas Malyshev • Looks like a spaceship: <=> • Mostly useful for sorting callbacks Spaceship Operator:
  32. Proprietary and Confidential // Pre Spacefaring^W PHP 7 function order_func($a,

    $b) { return ($a < $b) ? -1 : (($a > $b) ? 1 : 0); } // Post PHP 7 function order_func($a, $b) { return $a <=> $b; } Spaceship Operator
  33. • Double question mark: ?? • Will return left operand

    if not null, or the right operand • Will not raise a notice if the left operand is non-existant (like isset()) • Can be nested:
 $conf = $conf ?? $this->conf ?? static::$defaultConf; Null Coalesce Operator
  34. •$Closure->call($object, $closureArgs, $here); • Binds $this/scope to $object • Both

    must be the same • Similar to $Closure->bindTo() or Closure::bind() Bind Closure on Call
  35. Proprietary and Confidential class HelloWorld { private $greeting = "Hello";

    } $closure = function($whom) { echo $this->greeting . ' ' . $whom; } $obj = new HelloWorld(); $closure->call($obj, 'World'); // Hello World Bind Closure on Call
  36. • Simplify multiple use statements with common parent Group Use

    Declarations // Original use Framework\Component\SubComponent\ClassA; use Framework\Component\SubComponent\ClassB as ClassC; use Framework\Component\OtherComponent\ClassD; // With Group Use use Framework\Component\{ SubComponent\ClassA, SubComponent\ClassB as ClassC, OtherComponent\ClassD };
  37. • Also works for functions and constants: Group Use Statements

    (Cont.) use Framework\Component\{ SubComponent\ClassA, function OtherComponent\someFunction, const OtherComponent\SOME_CONSTANT };
  38. • Generators can now return a value • Retrieved by

    $generator->getReturn() Generator Return Expressions
  39. Proprietary and Confidential function gen() { yield "Hello"; yield "

    "; yield "World!"; return "Goodbye Moon!"; } $gen = gen(); foreach ($gen as $value) { echo $value; } // Outputs "Hello" on iteration 1, " " on iterator 2, and "World!" on iteration 3 echo $gen->getReturn(); // Goodbye Moon! Generator Return Values
  40. Generator Delegation function hello() { yield "Hello"; yield " ";

    yield "World!"; yield from goodbye(); } function goodbye() { yield "Goodbye"; yield " "; yield "Moon!"; }
  41. Generator Delegation $gen = hello(); foreach ($gen as $value) {

    echo $value; } 1. "Hello" 2. " " 3. "World!" 4. "Goodbye" 5. " " 6. "Moon!"
  42. • Like closures but for object instances • Uses new

    class($args) followed by a regular class definition • Can be namespaced • Support inheritance, traits, and interfaces • The internal name is based on it’s address • e.g. class@0x7fa77f271bd0 • If you extend a class, it will use that class as the prefix instead • This means that if you create anonymous classes in a loop it will actually create multiple of the same anonymous class Anonymous Classes
  43. Proprietary and Confidential $obj = new class($args) { public function

    __construct($args) { ... } }; $obj = new class ($args) extends Foo implements Bar { use Bat; }; Anonymous Classes
  44. Proprietary and Confidential foreach ($array as $value) { $instances[] =

    new class($value) extends ValueObject { ... } } $instance = new class($value) extends ValueObject { ... }; $instances[..] == $instances[..]; // where $value is the same $instances[..] != $instance; // These are different classes and 
 // will never match Anonymous Classes
  45. • Type-hint function/method arguments • Type-hint return values • Default:

    non-strict, will coerce types when possible • Allows for strict, applies to that file only, and only to the things it calls (with type-hints), not the things it defines. Scalar Type Hints
  46. Proprietary and Confidential function sendHttpStatus(int $statusCode, 
 string $message) {

    header('HTTP/1.0 ' .$statusCode. ' ' .$message); }
 sendHttpStatus(404, "File Not Found"); 
 // integer and string passed sendHttpStatus("403", "OK"); 
 // string "403" coerced to int(403) Scalar Type Hints: Non-Strict
  47. • Default non-strict behavior coerces • int(1) => function(int $foo)

    => float(1.0) • float(1.5) => function(int $foo) => int(1.0) • string("100") => function (int $foo) => int(100) Scalar Type Hints: Non-Strict
  48. • Strict Type Hints: declare(strict_types=1); • Must be the first

    line • Throws a \TypeException on mis-match declare(strict_types=1); // must be the first line try { sendHttpStatus(404, "File Not Found"); sendHttpStatus("403", "OK"); } catch (\TypeException $e) { var_dump($e); } 
 // Argument 1 passed to sendHttpStatus() must be of the type integer, string given Scalar Type Hints
  49. • Type hint return values • Allows for all type

    hints, not just scalars • Suffix argument list with a colon and the hint (same syntax as Hack) Return Type Hints function isValidStatusCode(int $statusCode): bool { return isset($this->statuses[$statusCode]); }