Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Typed Properties and more: What's coming in PHP 7.4?

Slides for PHPRussia 2019 talk on new features in PHP 7.4.

  • Inicia sesión para ver los comentarios

Typed Properties and more: What's coming in PHP 7.4?

  1. 1. Typed Properties and more: What’s coming in PHP 7.4? Nikita Popov
  2. 2. Release schedule (tentative) Now June 6th PHP 7.4 Alpha 1 July 18th PHP 7.4 Beta 1 – Feature freeze November 21st PHP 7.4 GA Release
  3. 3. Release schedule (tentative) Now June 6th PHP 7.4 Alpha 1 July 18th PHP 7.4 Beta 1 – Feature freeze November 21st PHP 7.4 GA Release December 2020 PHP 8.0 Release ≈
  4. 4. Overview ● FFI & Preloading ● Typed Properties ● Arrow Functions ● Covariant Return Types ● ??= ● Array Spread Operator ● WeakReference ● Deprecations
  5. 5. Overview ● FFI & Preloading => See Dmitry Stogov’s talk! ● Typed Properties ● Arrow Functions ● Covariant Return Types ● ??= ● Array Spread Operator ● WeakReference ● Deprecations
  6. 6. Typed Properties class User { public int $id; public string $name; } $user = new User; $user->id = 42; $user->name = []; // Uncaught TypeError: Typed property User::$name // must be string, array used
  7. 7. Nullability & Initialization class User { public int $id; // no null default public ?string $name; // also no null default (!) }
  8. 8. Nullability & Initialization class User { public int $id; // no null default public ?string $name; // also no null default (!) } $user = new User; var_dump($user->name); // Uncaught Error: Typed property User::$name must // not be accessed before initialization
  9. 9. Nullability & Initialization class User { public int $id; public ?string $name = null; } $user = new User; var_dump($user->name); // NULL
  10. 10. References class User { public int $id = 42; public string $name = "nikic"; } $user = new User; $id =& $user->id; $id = "not an id"; // Uncaught TypeError: Cannot assign string to // reference held by property User::$id of type int
  11. 11. Poor Man’s Intersection Types class Test { public ?Traversable $traversable; public ?Countable $countable; public $both = null; } $test = new Test; $test->traversable =& $test->both; $test->countable =& $test->both; $test->both = new ArrayIterator;
  12. 12. Poor Man’s Intersection Types class Test { public ?Traversable $traversable; public ?Countable $countable; public $both = null; } $test = new Test; $test->traversable =& $test->both; $test->countable =& $test->both; $test->both = new ArrayIterator; Effectively ?(Traversable&Countable)
  13. 13. Poor Man’s Intersection Types class Test { public ?Traversable $traversable; public ?Countable $countable; public $both = null; } $test = new Test; $test->traversable =& $test->both; $test->countable =& $test->both; $test->both = new AppendIterator; // Uncaught TypeError: Cannot assign AppendIterator // to reference held by property Test::$countable // of type ?Countable
  14. 14. Poor Man’s Typed Variables int $i = 0; $i = "foobar";
  15. 15. Poor Man’s Typed Variables $i =& int(0); $i = "foobar"; // Uncaught TypeError: Cannot assign string to // reference held by property class@anonymous::$prop // of type int
  16. 16. Poor Man’s Typed Variables function &int(int $i) { $obj = new class { public int $prop; }; $obj->prop = $i; $GLOBALS['huge_memory_leak'][] = $obj; return $obj->prop; } $i =& int(0); $i = "foobar"; // Uncaught TypeError: Cannot assign string to // reference held by property class@anonymous::$prop // of type int
  17. 17. Public Typed Properties? class User { private $name; public function getName(): string { return $this->name; } public function setName(string $name): void { $this->name = $name; } }
  18. 18. Public Typed Properties? class User { public string $name; }
  19. 19. Public Typed Properties? class User { public string $name; } What if additional validation will be needed?
  20. 20. Future: Property Accessors? class User { public string $name { get; set($name) { if (strlen($name) == 0) throw new Exception( 'Name cannot be empty'); $this->name = $name; } }; }
  21. 21. Arrow Functions array_filter( $values, function($v) use($allowedValues) { return in_array($v, $allowedValues); } );
  22. 22. Arrow Functions array_filter( $values, fn($v) => in_array($v, $allowedValues) );
  23. 23. Arrow Functions array_filter( $values, fn($v) => in_array($v, $allowedValues) ); Implicit use($allowedValues)
  24. 24. By-Value Binding $i = 0; $fn = fn() => $i++; $fn(); var_dump($i); // int(0)
  25. 25. By-Value Binding $fns = []; foreach ([1, 2, 3] as $i) { $fns[] = fn() => $i; } foreach ($fns as $fn) { echo $fn() . " "; } // Prints: 1 2 3 // Not: 3 3 3 (would happen with by-reference)
  26. 26. Syntax – Why fn? array_filter( $values, $v => in_array($v, $allowedValues) ); ECMAScript syntax
  27. 27. Syntax – Array Ambiguity $array = [ $a => $a + $b, $x => $x * $y, ]; Array of arrow functions? Or just a key-value map?
  28. 28. Syntax – Parsing // Looks like: Assignment expression ($x = [42] + ["foobar"]) => $x; // Looks like: Constant lookup + bitwise and (Type &$x) => $x; // Looks like: Ternary operator $a ? ($b): Type => $c : $d;
  29. 29. Syntax – Parsing // Looks like: Assignment expression ($x = [42] + ["foobar"]) => $x; // Looks like: Constant lookup + bitwise and (Type &$x) => $x; // Looks like: Ternary operator $a ? ($b): Type => $c : $d; Need special handling starting at ( But only know it’s an arrow function at =>
  30. 30. Future: Block Syntax array_filter( $values, fn($v) => in_array($v, $allowedValues) );
  31. 31. Future: Block Syntax array_filter( $values, fn($v) { // More code... return in_array($v, $allowedValues); } );
  32. 32. Future: Block Syntax array_filter( $values, fn($v) { // More code... return in_array($v, $allowedValues); } ); Basically like normal closure syntax, but with implicit variable capture
  33. 33. Covariant Return Types class A {} class B extends A {} class Producer { public function produce(): A {} } class ChildProducer extends Producer { public function produce(): B {} } Sound because $childFactory->create() still instanceof A.
  34. 34. Common Case: Self class Foo { public function fluent(): self {} } class Bar extends Foo { public function fluent(): self {} }
  35. 35. Ordering Issues class A { public function method(): B {} } class B extends A { public function method(): C {} } class C extends B {}
  36. 36. Ordering Issues class A { public function method(): B {} } class B extends A { public function method(): C {} } class C extends B {} Sound, but class C not available when verifying B. => No way to reorder classes “correctly”. => Will only work with autoloading (for now).
  37. 37. Contravariant Parameter Types class A {} class B extends A {} class Consumer { public function comsume(B $value) {} } class ChildConsumer extends Consumer { public function comsume(A $value) {} } Sound, but rarely useful.
  38. 38. Covariant Parameter Types? interface Event { ... } class SpecificEvent implements Event { ... } interface EventHandler { public function handle(Event $e); } class SpecificEventHandler implements EventHandler { public function handle(SpecificEvent $e) {} } Unsound, will never work!
  39. 39. Future: Generics interface Event { ... } class SpecificEvent implements Event { ... } interface EventHandler<E: Event> { public function handle(E $e); } class SpecificEventHandler implements EventHandler<SpecificEvent> { public function handle(SpecificEvent $e) {} }
  40. 40. ??= $options["something"] ??= new DefaultObject; // Roughly equivalent to: $options["something"] = $options["something"] ?? new DefaultObject;
  41. 41. ??= $options["something"] ??= new DefaultObject; Only created if $options["something"] is null
  42. 42. Array spread operator $array = [3, 4, 5]; return call(1, 2, ...$array); // call(1, 2, 3, 4, 5) $array = [3, 4, 5]; return [1, 2, ...$array]; // [1, 2, 3, 4, 5]
  43. 43. Array spread operator $array = new ArrayIterator([1, 2, 3]); return call(1, 2, ...$array); // call(1, 2, 3, 4, 5) $array = new ArrayIterator([1, 2, 3]); return [1, 2, ...$array]; // [1, 2, 3, 4, 5]
  44. 44. Array spread operator $array = ['y' => 'b', 'z' => 'c']; return ['x' => 'a', ...$array]; // Uncaught Error: Cannot unpack array with // string keys
  45. 45. Future: … in destructuring [$head, ...$tail] = $array;
  46. 46. Future: … in destructuring $array = [2 => 2, 1 => 1, 0 => 0]; [$head, ...$tail] = $array; What happens?
  47. 47. WeakReference $object = new stdClass; $weakRef = WeakReference::create($object); var_dump($weakRef->get()); // object(stdClass)#1 unset($object); var_dump($weakRef->get()); // NULL
  48. 48. WeakReference $this->data[get_object_id($object)] = [WeakReference::create($object), $data];
  49. 49. WeakReference $this->data[get_object_id($object)] = [WeakReference::create($object), $data]; Will be reused once object is destroyed
  50. 50. WeakReference $this->data[get_object_id($object)] = [WeakReference::create($object), $data]; Will be reused once object is destroyed Check $weakRef->get() != null to know whether the entry is still valid
  51. 51. WeakReference $this->data[get_object_id($object)] = [WeakReference::create($object), $data]; Will be reused once object is destroyed Check $weakRef->get() != null to know whether the entry is still valid Problem: Doesn’t keep $object alive, but keeps dead cache entry
  52. 52. Future: WeakMap $this->data = new WeakMap(); $this->data[$object] = $data; Does not keep $object alive; immediately drops cache entry when object destroyed
  53. 53. Deprecations Surprisingly few for now… …there will probably be more.
  54. 54. Ternary Associativity return $a == 1 ? 'one' : $a == 2 ? 'two' : 'other'; // was intended as: return $a == 1 ? 'one' : ($a == 2 ? 'two' : 'other'); // but PHP interprets it as: return ($a == 1 ? 'one' : $a == 2) ? 'two' : 'other';
  55. 55. Ternary Associativity return $a == 1 ? 'one' // Deprecated in 7.4. : $a == 2 ? 'two' // Compile error in 8.0. : 'other'; // was intended as: return $a == 1 ? 'one' : ($a == 2 ? 'two' : 'other'); // but PHP interprets it as: return ($a == 1 ? 'one' : $a == 2) ? 'two' : 'other';
  56. 56. Concatenation Precedence $a = 1; $b = 2; echo "Sum: " . $a+$b; // was intended as: echo "Sum: " . ($a+$b); // but PHP interprets it as: echo ("Sum: " . $a)+$b;
  57. 57. Concatenation Precedence $a = 1; $b = 2; echo "Sum: " . $a+$b; // Deprecated in PHP 7.4 // was intended as: echo "Sum: " . ($a+$b); // New behavior in PHP 8.0 // but PHP interprets it as: echo ("Sum: " . $a)+$b;
  58. 58. Short Open Tags (?) ● <? deprecated in 7.4, removed in 8.0 ● Only <?php and <?= supported ● (???) short_open_tag default value from On to Off in 7.4 Disclaimer: RFC accepted, but much push-back after voting.
  59. 59. 3v4l.org
  60. 60. Travis CI php: - 7.3 - 7.4snapshot - nightly install: - composer install --ignore-platform-reqs PHPUnit claims it is not PHP 8 compatible (it is)PHP 8
  61. 61. Docker ● https://github.com/devilbox/docker-php-fpm-7.4 ● https://github.com/devilbox/docker-php-fpm-8.0
  62. 62. Thank You! Questions?

×