O que tipos estritos fazem no PHP?

147

Eu vi a seguinte nova linha no PHP 7, mas ninguém realmente explica o que isso significa. Eu pesquisei no Google e tudo o que eles falam é que você estará ativando ou não como um tipo de pesquisa.

declare(strict_types = 1);

O que isso faz? Como isso afeta meu código? Devo fazer isso?

Alguma explicação seria legal.

sufuko
fonte
1
php.net/declare
JBES 10/02
5
Veja também php.net/manual/en/… para a diretiva
strict_types

Respostas:

153

No blog Treehouse :

Com o PHP 7, agora adicionamos tipos escalares. Especificamente: int, float, string e bool.

Ao adicionar dicas de tipo escalar e habilitar requisitos rígidos, espera-se que programas PHP mais corretos e com auto-documentação possam ser escritos. Também oferece mais controle sobre o seu código e pode facilitar a leitura do código.

Por padrão, as declarações de tipo escalares não são rigorosas, o que significa que elas tentarão alterar o tipo original para corresponder ao tipo especificado pela declaração de tipo. Em outras palavras, se você passar uma string que começa com um número para uma função que requer um float, ela pegará o número desde o início e removerá todo o resto. Passar um float para uma função que requer um int se tornará int (1).

Por padrão, o PHP converterá valores do tipo errado no tipo escalar esperado, se possível. Por exemplo, uma função que recebe um número inteiro para um parâmetro que espera uma string obterá uma variável do tipo string.

Tipos estritos desativados ( eval ):

<?php

  function AddIntAndFloat(int $a, float $b) : int
  {
      return $a + $b;
  }

  echo AddIntAndFloat(1.4, '2');
  /*
  * without strict typing, PHP will change float(1.4) to int(1)
  * and string('2') to float(2.0) and returns int(3)
  */

É possível ativar o modo estrito por arquivo. No modo estrito, apenas uma variável do tipo exato da declaração de tipo será aceita ou um TypeError será lançado. A única exceção a essa regra é que um número inteiro pode ser dado a uma função esperando um float. As chamadas de função de dentro das funções internas não serão afetadas pela declaração strict_types.

Para ativar o modo estrito, a declaração declare é usada com a declaração strict_types:

Tipos estritos ativados ( eval ):

<?php declare(strict_types=1);

  function AddIntAndFloat(int $a, float $b): int
  {
      return (string) $a + $b;
  }

  echo AddIntAndFloat(1.4,'2');
  // Fatal error: Uncaught TypeError: Argument 1 passed to AddIntAndFloat() must be of the type int, float given
  echo AddIntAndFloat(1,'2');
  // Fatal error: Uncaught TypeError: Argument 2 passed to AddIntAndFloat() must be of the type float, string given

  // Integers can be passed as float-points :
  echo AddIntAndFloat(1,1);
  // Fatal error: Uncaught TypeError: Return value of AddIntAndFloat() must be of the type integer, string returned

Exemplo de trabalho:

<?php

declare(strict_types=1);

function AddFloats(float $a, float $b) : float
{
    return $a+$b;
}

$float = AddFloats(1.5,2.0); // Returns 3.5

function AddFloatsReturnInt(float $a, float $b) : int
{
    return (int) $a+$b;
}

$int = AddFloatsReturnInt($float,1.5); // Returns 5

function Say(string $message): void // As in PHP 7.2
{
    echo $message;
}

Say('Hello, World!'); // Prints "Hello, World!"

function ArrayToStdClass(array $array): stdClass
{
    return (object) $array;
}

$object = ArrayToStdClass(['name' => 'azjezz','age' => 100]); // returns an stdClass

function StdClassToArray(stdClass $object): array
{
    return (array) $object;
}

$array = StdClassToArray($object); // Returns array

function ArrayToObject(array $array): object // As of PHP 7.2
{
    return new ArrayObject($array);
}

function ObjectToArray(ArrayObject $object): array
{
    return $object->getArrayCopy();
}

var_dump( ObjectToArray( ArrayToObject( [1 => 'a' ] ) ) ); // array(1 => 'a');
saif
fonte
3
O primeiro erro fatal mencionado no exemplo ativado de tipos estritos está errado. Conforme mencionado na documentação: "A única exceção a esta regra é que um número inteiro pode ser dado a uma função que espera um float". A chamada de função não falharia no int. Seria na corda embora.
Paul
63

strict_types afeta a coerção do tipo.

Usar dicas de tipo sem strict_typespode levar a erros sutis.

Antes de tipos estritos, int $xsignificava " $xdeve ter um valor coercível a um int". Qualquer valor que pudesse ser coagido a um intpassaria a dica de tipo, incluindo:

  • um int apropriado ( 242),
  • um float ( 10.17),
  • um bool ( true),
  • nullou
  • uma string com dígitos iniciais ( "13 Ghosts").

Ao definir strict_types=1, você diz ao mecanismo que int $xsignifica "$ x deve ser apenas um int apropriado, nenhum tipo de coerção é permitido". Você tem muita certeza de que está recebendo exatamente e apenas o que foi dado, sem nenhuma conversão e perda potencial.

Exemplo:

<?php
function get_quantity(): int {
    return '100 apples';
}
echo get_quantity() . PHP_EOL;

Rende um resultado potencialmente confuso:

Notice: A non well formed numeric value encountered in /Users/bishop/tmp/pmkr-994/junk.php on line 4
100

A maioria dos desenvolvedores esperaria, eu acho, uma intdica para significar "apenas um int". Mas não, significa "qualquer coisa como um int". A ativação de strict_types fornece o provável comportamento esperado e desejado:

<?php declare(strict_types=1);

function get_quantity(): int {
    return '100 apples';
}
echo get_quantity() . PHP_EOL;

Rendimentos:

Fatal error: Uncaught TypeError: Return value of get_quantity() must be of the type int, string returned in example.php:4

Eu acho que há duas lições aqui, se você usar dicas de tipo:

  • Use strict_types=1sempre.
  • Converta avisos em exceções, caso você esqueça de adicionar o strict_typespragma.
bispo
fonte
1
Isso já foi bem respondido há quase um ano;) #
emix
6
Na verdade, votei na outra resposta @emix. No entanto, senti que a questão de "devo fazê-lo" não foi abordada. Também senti que um exemplo mais compacto e chocante encorajaria as pessoas a usar strict_types.
bispo
1
Eu acho que esta pergunta aborda sucintamente o "Devo fazer isso?" parte da pergunta do PO. Retornar ao PHP após um hiato e isso foi muito útil.
Darragh Enright