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

PHP's Not Dead - PHP7 In Practice

PHP's Not Dead - PHP7 In Practice

Łukasz Szymański

August 20, 2016
Tweet

More Decks by Łukasz Szymański

Other Decks in Programming

Transcript

  1. szymanskilukasz // PHP 5 era code that will break.
 function

    handler(Exception $e) { ... }
 set_exception_handler('handler');
 
 // PHP 5 and 7 compatible.
 function handler($e) { ... }
 
 // PHP 7 only.
 function handler(Throwable $e) { ... }
  2. szymanskilukasz APC is opcode cache and data store APCu is

    only data store OPcache is only opcode cache
  3. szymanskilukasz APCu is APC stripped of opcode caching. APC is

    opcode cache and data store APCu is only data store OPcache is only opcode cache
  4. szymanskilukasz class PHPisNotDead
 {
 public function addIntegers($a, $b) {
 return

    $a + $b;
 }
 
 public function addFloats($a, $b) {
 return $a + $b;
 }
 
 public function reverseString($a) {
 return strrev($a);
 }
 
 public function isItTrue($a) {
 return $a ? 'yes' : 'no';
 }
 } PHP5
  5. szymanskilukasz class PHPisNotDead
 {
 public function addIntegers(MyInteger $a, MyInteger $b)

    {
 return $a + $b;
 }
 
 public function addFloats(MyFloat $a, MyFloat $b) {
 return $a + $b;
 }
 
 public function reverseString(MyString $a) {
 return strrev($a);
 }
 
 public function isItTrue($a) {
 return $a ? 'yes' : 'no';
 }
 } PHP5 + Value Objects
  6. szymanskilukasz PHP7 class PHPisNotDead
 {
 public function addIntegers(int $a, int

    $b) : int {
 return $a + $b;
 }
 
 public function addFloats(float $a, float $b) : float {
 return $a + $b;
 }
 
 public function reverseString(string $a) : string {
 return strrev($a);
 }
 
 public function isItTrue(bool $a) : string {
 return $a ? 'yes' : 'no';
 }
 }
  7. szymanskilukasz PHP7 class PHPisNotDead
 {
 public function addIntegers(int $a, int

    $b) : int {
 return $a + $b;
 }
 
 public function addFloats(float $a, float $b) : float {
 return $a + $b;
 }
 
 public function reverseString(string $a) : string {
 return strrev($a);
 }
 
 public function isItTrue(bool $a) : string {
 return $a ? 'yes' : 'no';
 }
 }
  8. szymanskilukasz PHP7 $php = new PHPisNotDead(); 
 var_dump($php->addIntegers(1.3, 5.7)); //

    int(6)
 var_dump($php->addFloats(4, '3.4')); // double(7.4)
 var_dump($php->reverseString(12345)); // string(5) "54321"
 var_dump($php->isItTrue(21.37)); // string(3) "yes"
  9. szymanskilukasz PHP7 $php = new PHPisNotDead(); 
 var_dump($php->addIntegers(1.3, 5.7)); //

    int(6)
 var_dump($php->addFloats(4, '3.4')); // double(7.4)
 var_dump($php->reverseString(12345)); // string(5) "54321"
 var_dump($php->isItTrue(21.37)); // string(3) "yes" WTF?
  10. szymanskilukasz PHP7 $php = new PHPisNotDead(); 
 var_dump($php->addIntegers(1.3, 5.7)); //

    int(6)
 var_dump($php->addFloats(4, '3.4')); // double(7.4)
 var_dump($php->reverseString(12345)); // string(5) "54321"
 var_dump($php->isItTrue(21.37)); // string(3) "yes" Coercive Mode (default)
  11. szymanskilukasz public function addIntegers(int $a,int $b) : int {
 return

    $a + $b;
 } 
 public function addIntegers($a, $b) { 
 $a = (int) $a; 
 $b = (int) $b; 
 return (int) ($a + $b);
 } PHP7
  12. szymanskilukasz public function addIntegers(int $a,int $b) : int {
 return

    $a + $b;
 } 
 public function addIntegers($a, $b) { 
 $a = (int) $a; 
 $b = (int) $b; 
 return (int) ($a + $b);
 } PHP7
  13. szymanskilukasz declare (strict_types=1); class PHPisNotDead
 {
 public function addIntegers(int $a,

    int $b) : int {
 return $a + $b;
 }
 
 public function addFloats(float $a, float $b) : float {
 return $a + $b;
 }
 
 public function reverseString(string $a) : string {
 return strrev($a);
 }
 
 public function isItTrue(bool $a) : string {
 return $a ? 'yes' : 'no';
 }
 } PHPisNotDead.php
  14. szymanskilukasz index.php require "PHPisNotDead.php";
 
 $php = new PHPisNotDead();
 var_dump($php->addIntegers(1.3,

    5.7)); // int(6)
 var_dump($php->addFloats(4, '3.4')); // double(7.4)
 var_dump($php->reverseString(12345)); // string(5) "54321"
 var_dump($php->isItTrue(21.37)); // string(3) "yes"
  15. szymanskilukasz index.php require "PHPisNotDead.php";
 
 $php = new PHPisNotDead();
 var_dump($php->addIntegers(1.3,

    5.7)); // int(6)
 var_dump($php->addFloats(4, '3.4')); // double(7.4)
 var_dump($php->reverseString(12345)); // string(5) "54321"
 var_dump($php->isItTrue(21.37)); // string(3) "yes" WTF2?
  16. szymanskilukasz declare (strict_types=1); class PHPisNotDead
 {
 public function addIntegers(int $a,

    int $b) : int {
 return $a + $b;
 }
 
 public function addFloats(float $a, float $b) : float {
 return $a + $b;
 }
 
 public function reverseString(string $a) : string {
 return strrev($a);
 }
 
 public function isItTrue(bool $a) : string {
 return $a ? 'yes' : 'no';
 }
 } PHPisNotDead.php
  17. szymanskilukasz declare (strict_types=1); class PHPisNotDead
 {
 public function addIntegers(int $a,

    int $b) : int {
 return $a + $b;
 }
 
 public function addFloats(float $a, float $b) : float {
 return $a + $b;
 }
 
 public function reverseString(string $a) : string {
 return strrev($a);
 }
 
 public function isItTrue(bool $a) : string {
 return $a ? 'yes' : 'no';
 }
 } PHPisNotDead.php
  18. szymanskilukasz PHPisNotDead.php declare (strict_types = 1);
 
 class PHPisNotDead
 {


    public function addIntegers(int $a, int $b) : int {
 return (string) ($a + $b);
 }
 
 public function addFloats(float $a, float $b) : float {
 return $a + $b;
 }
 
 public function reverseString(string $a) : string {
 return strrev($a);
 }
 
 public function isItTrue(bool $a) : string {
 return $a ? 'yes' : 'no';
 }
 }
  19. szymanskilukasz declare (strict_types = 1);
 
 require "PHPisNotDead.php";
 
 $php

    = new PHPisNotDead();
 var_dump($php->addIntegers(1.3, 5.7));
 var_dump($php->addFloats(4, '3.4'));
 var_dump($php->reverseString(12345));
 var_dump($php->isItTrue(21.37));
  20. szymanskilukasz declare (strict_types = 1);
 
 require "PHPisNotDead.php";
 
 $php

    = new PHPisNotDead();
 var_dump($php->addIntegers(1.3, 5.7));
 var_dump($php->addFloats(4, '3.4'));
 var_dump($php->reverseString(12345));
 var_dump($php->isItTrue(21.37));
  21. szymanskilukasz $php = new PHPisNotDead();
 try {
 var_dump($php->addIntegers(1.3, 5.7)); }

    catch (TypeError $error) {
 echo $error->getMessage();
 } catch (Error $error) {
 echo $error->getMessage();
 } catch (Exception $exception) {
 echo $exception->getMessage();
 } catch (Throwable $throwable) {
 echo $throwable->getMessage();
 }
  22. szymanskilukasz function should_return_nothing(): void {
 return 1; // Fatal error:

    A void function must not return a value
 }
 
 function lacks_return(): void {
 // valid
 }
 
 function returns_nothing(): void {
 return; // valid
 }
 
 function returns_null(): void {
 return null; // Fatal error: A void function must not return a value
 }
 
 function foobar(void $foo) {}
 // Fatal error: void cannot be used as a parameter type
  23. szymanskilukasz class Token {
 // Constants default to public
 const

    PUBLIC_CONST = 0;
 
 // Constants then also can have a defined visibility
 private const PRIVATE_CONST = 0;
 protected const PROTECTED_CONST = 0;
 public const PUBLIC_CONST_TWO = 0;
 
 //Constants can only have one visibility declaration list
 private const FOO = 1, BAR = 2;
 }
  24. szymanskilukasz //Interfaces only support public consts, // and a compile

    time error will be thrown // for anything else. // Mirroring the behavior of methods. 
 interface ICache {
 public const PUBLIC = 0;
 const IMPLICIT_PUBLIC = 1;
 }
  25. szymanskilukasz function answer(): ?int {
 return null; //ok
 }
 


    function answer(): ?int {
 return 42; // ok
 }
 
 function answer(): ?int {
 return new stdclass(); // error
 }
  26. szymanskilukasz function say(?string $msg) {
 if ($msg) {
 echo $msg;


    }
 }
 
 say('hello'); // ok -- prints hello
 say(null); // ok -- does not print
 say(); // error -- missing parameter
 say(new stdclass); //error -- bad type
  27. szymanskilukasz // nullability can be removed by a subclass interface

    Fooable {
 function foo(): ?Fooable;
 }
 interface StrictFooable extends Fooable {
 function foo(): Fooable; // valid
 }
  28. szymanskilukasz // but it cannot be added interface Fooable {


    function foo(): Fooable;
 }
 interface LooseFooable extends Fooable {
 function foo(): ?Fooable; // invalid
 }
  29. szymanskilukasz // Valid use: loosening the nullable marker // in

    a parameter: 
 interface Fooable {
 function foo(Fooable $f);
 }
 interface LooseFoo extends Fooable {
 function foo(?Fooable $f);
 }
  30. szymanskilukasz // Invalid use: tightening // the nullable marker in

    a parameter:
 interface Fooable {
 function foo(?Fooable $f);
 }
 interface StrictFoo extends Fooable {
 function foo(Fooable $f);
 }
  31. szymanskilukasz // If a value is not an array or

    instance of Traversable,
 // a TypeError will be thrown.
 function foo(iterable $iterable) {
 foreach ($iterable as $value) {
 // ...
 }
 }
 
 // If the returned value is not an array
 // or instance of Traversable, a TypeError will be thrown.
 function bar(): iterable {
 return [1, 2, 3];
 }
 
 // Parameters declared as iterable
 // may use null or an array as a default value
 function foo(iterable $iterable = []) {
 // ...
 }
  32. szymanskilukasz class Person
 {
 friend HumanResourceReport;
 
 protected $id;
 protected

    $firstName;
 protected $lastName;
 
 public function __construct($id, $firstName, $lastName)
 {
 $this->id = $id;
 $this->firstName = $firstName;
 $this->lastName = $lastName;
 }
 
 public function makeReport()
 {
 return new HumanResourceReport($this);
 }
 }
  33. szymanskilukasz class HumanResourceReport
 {
 private $person;
 
 public function __construct(Person

    $person)
 {
 $this->person = $person;
 }
 
 public function getFullName()
 {
 // HumanResourceReport would not have access to protected 
 // members of Person if not explicitly listed as a friend.
 return $this->person->firstName . ' ' . $this->person->lastName;
 }
 
 public function getReportIdentifier()
 {
 return "HR_REPORT_ID_{$this->person->id}";
 }
 }
  34. szymanskilukasz class HumanResourceReport
 {
 private $person;
 
 public function __construct(Person

    $person)
 {
 $this->person = $person;
 }
 
 public function getFullName()
 {
 // HumanResourceReport would not have access to protected 
 // members of Person if not explicitly listed as a friend.
 return $this->person->firstName . ' ' . $this->person->lastName;
 }
 
 public function getReportIdentifier()
 {
 return "HR_REPORT_ID_{$this->person->id}";
 }
 }
  35. szymanskilukasz $person = new Person(Uuid::uuid4(), 'Alice', 'Wonderland');
 $report = $person->makeReport();


    
 var_dump($report->getFullName()); 
 // string(16) "Alice Wonderland"
 var_dump($report->getReportIdentifier()); 
 // string(49) "HR_REPORT_ID_3F2504E0-4F89-41D3-9A0C-0305E82C3301"
  36. szymanskilukasz // Using positional arguments:
 array_fill(0, 100, 42);
 // Using

    named arguments:
 array_fill(start_index => 0, num => 100, value => 42);
  37. szymanskilukasz htmlspecialchars($string, default, default, false);
 // vs
 htmlspecialchars($string, double_encode =>

    false);
 
 $str->contains("foo", true);
 // vs
 $str->contains("foo", caseInsensitive => true);
  38. szymanskilukasz class Entry<KeyType, ValueType>
 {
 protected $key;
 protected $value;
 


    public function __construct(KeyType $key, ValueType $value)
 {
 $this->key = $key;
 $this->value = $value;
 }
 
 public function getKey(): KeyType
 {
 return $this->key;
 }
 
 public function getValue(): ValueType
 {
 return $this->value;
 }
 }
  39. szymanskilukasz class Entry<KeyType, ValueType>
 {
 protected $key;
 protected $value;
 


    public function __construct(KeyType $key, ValueType $value)
 {
 $this->key = $key;
 $this->value = $value;
 }
 
 public function getKey(): KeyType
 {
 return $this->key;
 }
 
 public function getValue(): ValueType
 {
 return $this->value;
 }
 }
  40. szymanskilukasz class Email {
 private $_email;
 
 public function __construct

    ($email) {
 // validation
 
 $this->_email = $email;
 }
 
 public function getValue() {
 return $this->_email;
 }
 }
  41. szymanskilukasz immutable class Email {
 public $email;
 
 public function

    __construct ($email) {
 // validation
 
 $this->email = $email;
 }
 }
  42. szymanskilukasz immutable class Email {
 public $email;
 
 public function

    __construct ($email) {
 // validation
 
 $this->email = $email;
 }
 }
  43. szymanskilukasz immutable class Email {
 public $email;
 
 public function

    __construct ($email) {
 // validation
 
 $this->email = $email;
 }
 }
  44. szymanskilukasz immutable class Email {
 public $email;
 
 public function

    __construct ($email) {
 // validation
 
 $this->email = $email;
 }
 }
 
 $email = new Email("[email protected]");
 $email->email = "[email protected]" // Call will result in Fatal Error
  45. szymanskilukasz class Email {
 public immutable $email;
 
 public function

    __construct ($email) {
 // validation
 
 $this->email = $email;
 }
 }
 
 $email = new Email("[email protected]");
 $email->email = "[email protected]" // Call will result in Fatal Error
  46. szymanskilukasz class BoxedInt {
 public int $value;
 }
 
 $i

    = new BoxedInt();
 $i->value = 'oops'; 
 // Catchable fatal error:
 // property BoxedInt::$value must be of
 // the type integer, string given