O PHP evoluiu bastante ao longo dos anos, e uma das melhorias mais importantes foi a introdução de tipagens estáticas no código. Antigamente, o PHP era uma linguagem muito mais flexível (e caótica), onde variáveis podiam mudar de tipo sem muita preocupação. Mas hoje, com tipagem forte e clara, você pode aumentar a segurança e a legibilidade do seu código, tornando-o mais previsível e fácil de manter.

Motivos para usar tipagem
  1. Menos erros inesperados: Com a tipagem definida, você evita passar dados do tipo errado para funções ou métodos. Isso ajuda a capturar bugs mais cedo, economizando tempo na depuração.
  2. Autocomplete mais eficiente: Se você usa um editor como o VSCode ou PHPStorm, a tipagem melhora o autocomplete, porque o editor sabe exatamente quais tipos estão sendo usados.
  3. Código mais legível: Quando você define os tipos esperados em funções e métodos, qualquer pessoa (incluindo você no futuro) que leia o código vai entender melhor o que está acontecendo e o que se espera de cada função.
Tipos primitivos

A tipagem primitiva permite definir tipos básicos como int, float, string e bool. Por exemplo, vamos criar uma função que some dois números:

Terminal window
function soma(int $a, int $b) {
return $a + $b;
}

Como pode ver, podemos definir o tipo de parâmetro que queremos na assinatura do método, assim você conseguirá saber os tipos que a função espera. Indo além, nós tambem conseguimos tipar o retorno:

Terminal window
function soma(int $a, int $b): int {
return $a + $b;
}

Bom, sabemos que a função, independente de tudo, vai sempre nos retornar um inteiro, assim não precisamos tratar outros casos!

Objetos

Quando trabalhamos com objetos, podemos especificar que uma variável ou parâmetro deve ser de uma classe ou interface específica. Isso é útil para garantir que funções ou métodos recebam e retornem instâncias de classes corretas.

Imagine que estamos desenvolvendo um sistema que faz a gestão de pedidos. Cada pedido está associado a um cliente. Usando a tipagem, podemos garantir que apenas instâncias válidas de Cliente sejam passadas para o pedido.

Terminal window
class Cliente {
public string $nome;
public function __construct(string $nome) {
$this->nome = $nome;
}
}
class Pedido {
private Cliente $cliente;
private float $valor;
public function __construct(Cliente $cliente, float $valor) {
$this->cliente = $cliente;
$this->valor = $valor;
}
public function detalhes(): void {
echo "Cliente: " . $this->cliente->getNome() . PHP_EOL;
echo "Valor do pedido: R$ " . $this->valor . PHP_EOL;
}
}
$cliente = new Cliente('Carlos Jr');
$pedido = new Pedido($cliente, 250.50);
$pedido->detalhes();
// Saída:
// Cliente: Carlos Jr
// Valor do pedido: R$ 250.5
Arrays

A tipagem do array não tem segredos no PHP, podemos tipar usando a palavra reservada array.

Terminal window
function imprime(array $nomes) {
foreach ($nomes as $nome) {
echo "Nome: " . $nome . PHP_EOL;
}
}

O PHP ainda não nos permite tipar fortemente o array, por exemplo um caso em que precisamos de um array de inteiros, para isso existem as anotações do PHPDoc, onde podemos definir mais claramente, por exemplo:

Terminal window
/**
* @param array<int> $valores
* @return int[]
*/
function dobro(array $valores): array {
$dobro = [];
foreach ($valores as $valor) {
$dobro[] = $valor * 2;
}
return $dobro;
}

Com isto, conseguimos definir que nossa função aceitará um array de inteiros e retornará um array de inteiros!

Os PHPDocs são bem complexos e existem muitas possibilidades. veja mais em psalm.dev

Union Types

A tipagem vista acima as vezes pode ser muito rígida, para isso, a partir do PHP 8, foram introduzidas os ‘union types’, permitindo que passemos mais de um tipo para uma propriedade, retorno ou seja o que for. Muito útil quando precisamos ser mais flexível com a tipagem, mas ainda sim queremos manter uma certa segurança no tipo em que recebemos. A união de tipos pode ser declarada usando um pipe | entre os tipos.

Agora imagine a mesma função de soma, só que recebendo um float:

Terminal window
function soma(int|float $a, int|float $b): int|float {
return $a + $b;
}

Pronto, agora nossa função pode receber tanto int quanto float, e tambem retorno int OU float.

Veja mais em php.watch

Intersect Types

Já no PHP 8.1 temos a interseção de tipos, que permitem que um valor seja uma instância de múltiplas classes ou interfaces ao mesmo tempo. Isso é útil em casos onde você precisa garantir que um objeto implemente múltiplas funcionalidades. A interseção de tipos pode ser declarada com um &.

No exemplo abaixo, a função necessita que o parâmetro receba um valor que implemente tanto o Iterator quanto o Countable, e isso pode ser MUITO útil quando se trabalha com orientação à objetos.

Terminal window
function conte_e_itere(Iterator&\Countable $valor) {
foreach($valor as $val) {}
count($valor);
}

Caso passe um valor que não implemente ambas as interfaces, o PHP irá gerar um erro.

Veja mais em php.watch

Nullable

O operador ? permite que você especifique que um tipo pode ser null, algo muito útil quando certos valores são opcionais ou podem não existir, o que acontece com frequência.

Terminal window
function novoUsuario(string $email, ?string $nome) {
if (is_null($nome)) {
$nome = 'Sem nome';
}
return new Usuario($email, $nome);
}

Neste exemplo, o parâmetro nome pode ser tanto string como null.

Tipagem estrita

Por padrão, o PHP tenta “ajustar” tipos de dados automaticamente (tipagem fraca), o que significa que ele converte valores conforme necessário. Por exemplo, você pode passar uma string para uma função que espera um número, e o PHP converterá essa string em um número sem gerar erros.

Terminal window
function soma(int $a, int $b): int {
return $a + $b;
}
echo soma(5, '10'); // Funciona e converte a string '10' para o número 10

Para evitar este tipo de comportamento, precisamos declarar em todos os arquivos, que não queremos essa conversão usando:

Terminal window
declare(strict_types=1);

Com isso, o PHP exige que os tipos exatos definidos nas assinaturas das funções sejam respeitados. Isso garante um comportamento mais previsível e evita conversões automáticas que podem causar bugs.

Terminal window
function soma(int $a, int $b): int {
return $a + $b;
}
echo soma(5, '10'); // Gera um erro, pois '10' é uma string e não um int
Conclusão

Não subestime o poder das tipagens, elas existem para serem usadas. Quando se trabalha em equipe, as tipagens ajudará e muito a legibilidade dos seus projetos PHP.