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

Criando Aplicações Robustas em PHP com Tipos

Criando Aplicações Robustas em PHP com Tipos

Os tipos são ferramentas fundamentais para a construção de uma aplicação robusta. Eles são utilizados para a prevenção de erros durante a execução e auxiliam na legibilidade e manutenção do código. Nesta palestra serão apresentadas a definição de tipos e por que utilizá-los, sistema de tipos, tipagem estática e dinâmica, tipagem forte e fraca, como funciona o sistema de tipos e a evolução dos tipos em PHP. Abordaremos as novidades relacionadas a tipos que foram adicionadas ao longo do tempo na linguagem tais como enums e intersection types que estarão disponíveis na versão mais nova do PHP. E, por fim, falaremos como expandir o sistema de tipos do PHP e torná-lo ainda mais poderoso com o auxílio de ferramentas de análise estática como PHPStan e Psalm. Assista esta palestra e aprenda como tirar vantagem dos tipos na linguagem mais querida da web!

Marcel dos Santos

November 22, 2021
Tweet

More Decks by Marcel dos Santos

Other Decks in Programming

Transcript

  1. Interaja nas mídias sociais! 
 
 - fale sobre o

    evento, palestrantes e conteúdo - tire fotos do evento e publique 
 - interaja com outros participantes do evento - tire dúvidas ou dê feedbacks para os palestrantes
  2. os tipos podem ser considerados como um conjunto de valores,

    isto é, os valores são agrupados por tipos
  3. eles de fi nem a forma como um valor é

    armazenado é representado
  4. um tipo é uma classi fi cação do dado que

    de fi ne a operação que pode ser feita sobre aquele dado, o signi fi cado do dado e o conjunto de valores permitidos
  5. a medida que a complexidade de um software cresce, é

    necessário que o código possua garantias de corretude
  6. os erros que acontecem em tempo de execução e que

    podem causar problemas na aplicação…
  7. …podem ser transformados em erros em tempo de compilação e

    evitar causar sérios problemas na aplicação
  8. o TypeScript é uma linguagem criada para fornecer checagem de

    tipo em tempo de compilação para o JavaScript
  9. um sistema de tipos é um conjunto de regras que

    atribui e impõe tipos para elementos de uma linguagem de programação
  10. um sistema de tipos permite atribuir tipos através de uma

    notação no código ou implicitamente deduzindo o tipo de certos elementos baseados no contexto
  11. utiliza-se o sistema de tipos para projetar código menos propenso

    a erros, melhor componentizável e fácil de entender
  12. um código correto significa que ele se com- porta de

    acordo com a sua especi fi cação, produz resultados esperados e sem criar erros em tempo de execução
  13. ao utilizar um sistema de tipos transforma-se o que seria

    um erro em tempo de execução que poderia acontecer em produção e afetar o cliente final…
  14. …em um inofensivo erro em tempo de compilação que pode

    ser corrigido antes de fazer o deploy do código
  15. um sistema de tipos permite otimização em tempo de execução,

    funciona como documentação e pode ser interno ou externo a linguagem
  16. os tipos primitivos são aqueles cujos valores são atômicos, ou

    seja, não podem ser decompostos em valores mais simples
  17. os tipos recursivos é de fi nido em termos de

    si e a cardinalidade de tipos recursivos é in fi nita
  18. em uma linguagem com tipagem forte a conversão de tipos

    deve ser feita de forma explícita e operações entre valores de tipos diferentes não são permitidas
  19. em uma linguagem com tipagem fraca a conversão de tipos

    é feita de forma implícita e operações entre valores de tipos diferentes são permitidas e feitas de forma automática
  20. o PHP possui tipagem dinâmica e fraca pois a veri

    fi cação de tipos é feita em tempo de execução e é feita a conversão automática de tipos em operações com tipos diferentes
  21. ao utilizar ferramentas de análise estática como Phan, PHPStan e

    Psalm é possível realizar a veri fi cação de tipos em tempo de “compilação” na linguagem
  22. a veri fi cação de tipo ou type checking é

    um processo de veri fi cação e garantia das restrições de tipos
  23. a verificação de tipo pode ser executada em tempo de

    compilação ou tempo de execução
  24. ela garante a integridade do dado, impõe restrições de acesso

    e interpreta os dados como pretendidos pelo(a) programador(a)
  25. a inferência de tipos permite que o(a) programador(a) não declare

    o tipo mas que o compilador ou interpretador conheça o tipo com base no valor informado
  26. um erro de tipo ocorre se o programa executa 


    uma operação com tipos incompatíveis
  27. / / variables of several different types 
 $a_boolean =

    true; $an_int = 10; $a_float = 3.14; $a_string = 'joe'; $a_null = null; $a_array = []; $a_callable = function() { return 'Hey!'; }; $a_object = new stdClass;
  28. / / get variable type using var_dump() function var_dump($a_boolean); /

    / bool(true) var_dump($an_int); / / int(10) var_dump($a_float); / / float(3.14) var_dump($a_string); / / string(3) "joe" var_dump($a_null); / / NULL var_dump($a_array); / / array(0) {} var_dump($a_callable); / / object(Closure)#1 (0) {} var_dump($a_object); / / object(stdClass)#2 (0) {}
  29. / / get variable type using gettype() function echo gettype($a_boolean);

    / / boolean echo gettype($an_int); / / integer echo gettype($a_float); / / double echo gettype($a_string); / / string echo gettype($a_null); / / NULL echo gettype($a_array); / / array echo gettype($a_callable); / / object echo gettype($a_object); / / object
  30. / / get variable type using get_debug_type() / / function

    available on PHP 8.0 echo get_debug_type($a_boolean); / / bool echo get_debug_type($an_int); / / int echo get_debug_type($a_float); / / float echo get_debug_type($a_string); / / string echo get_debug_type($a_null); / / null echo get_debug_type($a_array); / / array echo get_debug_type($a_callable); / / Closure echo get_debug_type($a_object); / / stdClass
  31. / / check if variables are from a specif i

    c / / type using is_*() functions var_dump(is_bool($a_boolean)); / / bool(true) var_dump(is_bool($an_int)); / / bool(false) 
 var_dump(is_int($an_int)); / / bool(true) var_dump(is_int($a_float)); / / bool(false) 
 var_dump(is_float($a_float)); / / bool(true) var_dump(is_float($a_string)); / / bool(false)
  32. / / check if variables are from a specif i

    c / / type using is_*() functions var_dump(is_string($a_string)); / / bool(true) var_dump(is_string($a_null)); / / bool(false) 
 var_dump(is_array($a_array)); / / bool(true) var_dump(is_array($a_object)); / / bool(false) 
 var_dump(is_null($a_null)); / / bool(true) var_dump(is_null($a_array)); / / bool(false)
  33. / / explicit type conversion var_dump((bool) "1.5"); / / bool(true)

    var_dump((int) "1.5"); / / int(1) var_dump((float) "1.5"); / / float(1.5) var_dump((string) 1.5); / / string(3) "1.5"
  34. / / explicit type conversion var_dump((array) 1.5); / / array(1)

    { [0] = > float(1.5) } var_dump((array) "1.5"); / / array(1) { [0] = > string(3) "1.5" } var_dump((object) 1.5); / / object(stdClass)#1 (1) {["scalar"] = > … var_dump((object) "1.5"); / / object(stdClass)#1 (1) {["scalar"] = > …
  35. / / implicit or automatic type conversion / / using

    `+` operator 
 $var = "0"; var_dump($var); / / string(2) "0" $var += 5; var_dump($var); / / int(5) $var = $var + 3.1; var_dump($var); / / float(8.1)
  36. as declarações de tipos garantem que o valor é do

    tipo especi fi cado no momento da chamada
  37. as declarações de tipos podem ser utiliza- das em argumentos

    de funções, retornos de valores e propriedades de classe
  38. caso o valor informado não seja do tipo especi fi

    cado na declaração do tipo a exceção TypeError é lançada*
  39. declarações de tipos 
 
 1. tipos escalares 
 2.

    tipos compostos 
 3. classes e interfaces 
 4. object, mixed, self, parent, never 
 5. union types e intersection type 
 6. enums
  40. / / type declaration using classes class Mammal {} class

    Cat extends Mammal {} class Duck {} function sayHi(Mammal $mammal) { echo 'Hi ' . get_class($mammal) . '!'; } sayHi(new Mammal); / / Hi Mammal! sayHi(new Cat); / / Hi Cat! 
 sayHi(new Duck); 
 / / Uncaught TypeError: Argument 1 passed to / / sayHi() must be an instance of Mammal, instance of Duck given
  41. o PHP realiza, por padrão, a conversão automática de tipos

    de um valor para o tipo esperado quando necessário
  42. / / not using strict types function sum(int $a, int

    $b) { return $a + $b; } var_dump(sum(1, 2)); / / int(3) var_dump(sum(1.5, 2.5)); / / int(3) var_dump(sum("2", "5")); / / int(7) var_dump(sum(true, true)); / / int(2)
  43. pode-se ativar o modo estrito para garantir que a conversão

    automática de tipos não seja realizada
  44. e, caso o valor tenha um tipo incompatível com o

    tipo esperado, a exceção TypeError será lançada
  45. / / using strict types declare(strict_types=1); / / throws an

    exception when a value / / with incompatible type are provided function sum(int $a, int $b) { return $a + $b; } var_dump(sum(1, 2)); / / int(3) 
 var_dump(sum(1.5, 2.5)); Uncaught TypeError: Argument 1 passed to sum() must be of the type integer, float given
  46. / / the value returned is converted / / to

    the correct type function sum($a, $b) : int { return $a + $b; } var_dump(sum(1, 2)); / / int(3) var_dump(sum(1.7, 2.5)); / / int(4) var_dump(sum(true, true)); / / int(2)
  47. declare(strict_types=1); / / a type exception is thrown function sum($a,

    $b) : int { return $a + $b; } var_dump(sum(1, 2)); / / int(3) var_dump(sum(1.7, 2.5)); / / Uncaught TypeError: sum() : Return value must be of type int, float returned
  48. / / code with unnecessary boilerplate to enforce type contracts

    class User { /** @var int $id * / private $id; /** @var string $name * / private $name; public function _ _ construct(int $id, string $name) { $this - > id = $id; $this - > name = $name; } public function getId() : int { return $this - > id; } / / setId, getName and setName implementation . . . }
  49. / / more concise code with same type contracts class

    User { public int $id; public string $name; public function _ _ construct(int $id, string $name) { $this - > id = $id; $this - > name = $name; } }
  50. se uma propriedade tipada não tiver um valor padrão ela

    será considerada não inicializada
  51. / / uninitialized properties and / / default null (PHP

    7.3) class User { public $id; public $name; } $user = new User; var_dump($user); / / class User#1 (2) { / / public $id = > NULL / / public $name = > NULL / / }
  52. / / uninitialized properties and no / / null default

    (PHP 7.4) class User { public int $id; / / no null default public ?string $name; / / also no null default } $user = new User; var_dump($user); / / object(User)#1 (0) { / / ["id"] = > uninitialized(int) / / ["name"] = > uninitialized(?string) / / }
  53. ao tentar fazer a leitura de uma propriedade não inicializada

    será lançado um erro do tipo TypeError
  54. / / try to access a uninitialized property class User

    { public int $id; public string $name; } $user = new User; echo $user - > id; / / Uncaught Error: Typed property User : : $id must 
 / / not be accessed before initialization
  55. um nullable type é um tipo que pode ser de

    um tipo especí fi co ou nulo e é representado por ?Type
  56. / / annotate email property with nullable string type class

    Person { function _ _ construct( public string $name, public ?string $email, ) {} } 
 
 $person1 = new Person('Alice', '[email protected]'); $person2 = new Person('Bob', null);
  57. var_dump($person1); var_dump($person2); / / object(Person)#1 (2) { / / ["name"]

    = > string(5) "Alice" / / ["email"] = > string(17) "[email protected]" / / } / / object(Person)#2 (2) { / / ["name"] = > string(3) "Bob" / / ["email"] = > NULL / / }
  58. o tipo nullable possui a sintaxe ?Type e pode ser

    do tipo Type|null, isto é, Type ou null
  59. declare(strict_types=1); / / using union type to annotate a function

    parameter function power(float|int $number, int $exponent) : int|float { return $number * * $exponent; } echo power(3, 2); / / 9 echo power(3.5, 2); / / 12.25 echo power('3', 2.5); / / Uncaught TypeError: power() : Argument #1 ($number) must be of type int|float, string given
  60. o suporte nativo permite a garantia de tipos pelo interpretador

    PHP e reduz a necessida- de de docblocks
  61. um intersection type permite anotar o tipo de um valor

    que satisfaça múltiplas restrições de tipos ao mesmo tempo
  62. / / using intersection type to annotate a property of

    a test / / class that represents a mocked object class CreateUserTest { private MockObject&UserRepository $userRepositoryMock; }
  63. uma enum de fi ne um novo tipo que possui

    número fi xo e limitado de valores possíveis
  64. / / creates an enum for the suits of a

    deck enum Suit { case Hearts; case Diamonds; case Clubs; case Spades; } $value = Suit : : Hearts; var_dump($value); / / enum(Suit : : Hearts)
  65. esse tipo de valor é chamado de pure case e

    uma enum que contém apenas pure cases é chamada de pure enum
  66. / / annotate a function parameter with an enum type

    function pick_a_card(Suit $suit) {} pick_a_card($value); / / ok pick_a_card(Suit : : Clubs); / / ok pick_a_card('Spades'); / / Fatal error: Uncaught TypeError: pick_a_card() : Argument #1 ($suit) must be of type Suit, string given
  67. contudo, existem casos de usos em que é necessário ter

    equivalentes escalares para, por exemplo, persistir em uma base de dados
  68. / / create an enum backed with scalar values enum

    Suit: string { case Hearts = 'H'; case Diamonds = 'D'; case Clubs = 'C'; case Spades = 'S'; } var_dump(Suit : : Hearts); / / enum(Suit : : Hearts) var_dump(Suit : : Hearts - > name); / / string(6) "Hearts" var_dump(Suit : : Hearts - > value); / / string(1) "H"
  69. um case que tem um equivalente escalar é chamado de

    backed case pois é “suportado" por um valor mais simples
  70. um backed enum implementa a interface interna BackedEnum que expõe

    dois métodos adicionais que são from e tryFrom
  71. o método from() recebe um tipo escalar e retorna o

    case correspondente e, caso o valor não seja encontrado, a exceção ValueError é lançada
  72. / / create an order status enum enum OrderStatus: string

    { case PendingPayment = 'pending_payment'; case Processing = 'processing'; case Completed = 'completed'; case Refunded = 'refunded'; case Cancelled = 'cancelled'; }
  73. / / create an enum value using from() method with

    a valid value $orderStatus = OrderStatus : : from('processing'); var_dump($orderStatus); / / enum(OrderStatus : : Processing) echo $orderStatus - > value; / / processing / / try to create an enum value using from() method with an invalid value $orderStatus = OrderStatus : : from('non_existent'); / / Fatal error: Uncaught ValueError: "non_existent" is not a / / valid backing value for enum "OrderStatus" / / try to create an enum value using tryFrom() method with an invalid value $orderStatus = OrderStatus : : tryFrom('non_existent'); var_dump($orderStatus); / / null
  74. uma função ou método declarados com o tipo de retorno

    never indica que nunca retornará um valor…
  75. / / creates a function with never return type function

    redirect(string $url) : never { echo "redirected to $url . . . \n"; header('Location: ' . $url); exit(); } redirect('https: / / w w w .example.com'); / / redirected to https: / / w w w .example.com . . . 
 / / The rest of the code will not be executed! echo 'this will not be shown . . . ';
  76. o objetivo do tipo de retorno never é indicar uma

    função que previne que o resto do código chamado seja executado
  77. se uma função ou método com o tipo de retorno

    never não lançar uma exceção ou não terminar o programa será lançada a exceção TypeError
  78. / / create a function with never return type function

    dispatch(string $message) : never { echo $message; } dispatch('test'); / / Uncaught TypeError: dispatch() : never - returning / / function must not implicitly return
  79. o suporte ao tipo de retorno never torna possível não

    utilizar mais a annotation @return noreturn
  80. o PHP tem tido uma enorme evolução em relação a

    tipos e tem se tornado uma linguagem mais robusta
  81. porém, sem perder a fl exibilidade e a pequena curva

    de aprendizado que o torna uma linguagem tão democrática
  82. as novas funcionalidades ajudarão o seu código a ter mais

    garantias, ser mais expressivo e te dar mais poderes