[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.

Fee39f0c0ffb29d9ac21607ed188be6b?s=128

Davey Shafik

June 27, 2015
Tweet

Transcript

  1. What to Expect When You’re Expecting: PHP 7

  2. 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
  3. Let’s start a conversation about mental health in tech mhprompt.org

  4. PHP 7.0

  5. None
  6. Mar 15
 2015 Jun 15
 2015 Oct 15 2015 Feature

    Freeze Finalize Implementation Release Candidates PHP 7.0 Final Alphas/Betas (we are here)
  7. Removal of Deprecated Features

  8. Alternative PHP Tags

  9. • ASP Tags: <%, <%= and %> • Script Tags:

    <script language="php"></script> Alternative PHP Tags
  10. POSIX Compatible Regular Expressions

  11. • All ereg_* functions removed • Use preg_* instead Posix

    Compatible Regular Expressions
  12. ext/mysql

  13. • All mysql_* functions removed • Use mysqli_* for direct

    migration • Use mysqli OO or PDO instead ext/mysql
  14. Multiple Default Cases in Switch

  15. 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
  16. Performance

  17. 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
  18. 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
  19. 2.4X

  20. 59%

  21. AST Abstract Syntax Tree

  22. AST — Abstract Syntax Tree

  23. • 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
  24. Uniform Variable Syntax

  25. • 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
  26. 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']()
  27. Uniform Variable Syntax: New Syntax

  28. Proprietary and Confidential $foo()['bar']() [$obj1, $obj2][0]->prop getStr(){0} Missing Combinations

  29. Proprietary and Confidential $foo['bar']::$baz $foo::$bar::$baz $foo->bar()::baz() Nested Static Accessors

  30. Proprietary and Confidential foo()() $foo->bar()() Foo::bar()() $foo()() Nested Parentheses

  31. Proprietary and Confidential (...)['foo'] (...)->foo (...)->foo() (...)::$foo (...)::foo() (...)() Arbitrary

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

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

    (or better yet: don’t use globals!) No Longer Supported
  34. Assertions

  35. • 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
  36. zend.assertions = 1 ; Enable assertions assert.exception = 1 ;

    Throw exception on failure Assertions
  37. 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
  38. Error Handling

  39. Catchable Fatal Error: Call to member function on non-object

  40. • 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
  41. 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
  42. Engine Exceptions

  43. 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
  44. • Can be handled gracefully • Finally blocks are called

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

    \Error implements \Throwable ├── \TypeError extends \Error ├── \ParseError extends \Error └── \AssertionError extends \Error Exception Hierarchy
  46. 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
  47. \Error

  48. • 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
  49. \ParseError

  50. • 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() { }
  51. 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 }
  52. \TypeError

  53. • 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); }
  54. 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
  55. \AssertionError

  56. • 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); }
  57. 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
  58. New Features

  59. \o/

  60. Combined Comparison Operator

  61. Spaceship Operator: T_SPACESHIP

  62. • 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:
  63. 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
  64. Unicode Codepoint Escape Syntax

  65. •\u{CODEPOINT} • e.g. ! can be expressed as "\u{1F49A}" Unicode

    Codepoint Escape Syntax
  66. Null Coalesce Operator As close as we’re going to get

    to an ifsetor
  67. • 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
  68. Bind Closure on Call

  69. •$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
  70. 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
  71. Group Use Declarations

  72. • 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 };
  73. • Also works for functions and constants: Group Use Statements

    (Cont.) use Framework\Component\{ SubComponent\ClassA, function OtherComponent\someFunction, const OtherComponent\SOME_CONSTANT };
  74. Generator Enhancements

  75. • Generators can now return a value • Retrieved by

    $generator->getReturn() Generator Return Expressions
  76. 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
  77. • Yield other generators or iterable structures — sub-generators •

    Uses yield from Generator Delegation
  78. Generator Delegation function hello() { yield "Hello"; yield " ";

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

    echo $value; } 1. "Hello" 2. " " 3. "World!" 4. "Goodbye" 5. " " 6. "Moon!"
  80. Anonymous Classes

  81. • 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
  82. Proprietary and Confidential $obj = new class($args) { public function

    __construct($args) { ... } }; $obj = new class ($args) extends Foo implements Bar { use Bat; }; Anonymous Classes
  83. 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
  84. Scalar Type Hints

  85. • 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
  86. 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
  87. • 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
  88. • 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
  89. • 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]); }
  90. What Next?

  91. • https://github.com/rlerdorf/php7dev • https://github.com/janatzend/docker-php7-nightly-build • http://gophp7.org/gophp7-ext/ • https://wiki.php.net/rfc#php_70 What Next?

  92. Feedback & Questions: 
 Feedback: https://joind.in/
 Twitter: @dshafik Email: me@daveyshafik.com

    Slides: http://daveyshafik.com/slides 14243