Em resumo: O PHP tem tipagem dinâmica: o tipo de um valor só é conhecido em tempo de execução e, sem mais indicações, o PHP converte automaticamente os valores quando necessário. Desde o PHP 7, porém, é possível atribuir tipos a parâmetros, retornos e propriedades, e declare(strict_types=1) torna a verificação rigorosa. Quem conhece as regras e usa comparações estritas com === evita toda uma classe de erros de lógica e de segurança.
Tipagem dinâmica, mas não sem tipos
Em PHP, com $preis = 19.90; não é preciso indicar um tipo. O PHP reconhece que se trata de um número de vírgula flutuante. Se o valor for mais tarde combinado com uma cadeia de caracteres, o PHP converte-o. Este comportamento chama-se type juggling, ou seja, conversão automática de tipos. Facilita a iniciação, mas pode levar a resultados surpreendentes.
Para quem decide, isto é relevante porque muitas aplicações PHP mais antigas foram escritas sem indicações de tipo. Esse código é mais difícil de verificar e de modernizar. Os projetos mais recentes usam os tipos de forma consistente, o que torna os erros visíveis mais cedo e só assim permite que a análise estática com ferramentas como o PHPStan ou o Psalm tenha verdadeiro efeito.
Os tipos do PHP em resumo
O manual do PHP indica nove tipos internos que qualquer expressão pode ter. Habitualmente são divididos em três grupos:
| Grupo | Tipos | Exemplo |
|---|---|---|
| Tipos escalares | bool, int, float, string |
true, 42, 3.5, "Text" |
| Tipos compostos | array, object, callable |
[1, 2], new DateTime() |
| Tipos especiais | null, resource |
null, um ficheiro aberto |
Para verificações de tipo, o manual recomenda as funções is_*(), como is_int(). Para inspeção, é adequado o get_debug_type(), que desde o PHP 8.0.0 devolve os nomes de tipo habituais, enquanto o gettype(), mais antigo, devolve por exemplo "integer" e "double".
Além da conversão automática, existe a explícita: com um cast como (int) $wert ou com settype(), o próprio código determina que tipo um valor deve ter. É habitual com entradas de formulários, porque tudo o que chega através de $_GET ou $_POST é, de início, uma cadeia de caracteres ou um array. Um cast, porém, não verifica se o valor fazia sentido: "abc" passa silenciosamente a 0. Para entradas, uma verificação a sério com filter_var() é por isso, em regra, a melhor escolha.
As classes e as interfaces são também tipos em PHP. Uma função pode, portanto, exigir que um parâmetro seja um objeto de uma determinada classe ou cumpra uma determinada interface. Como interagem classes, interfaces e enums explica-o a página Programação orientada a objetos em PHP.
Declarações de tipo: do PHP 7.1 ao 8.3
As declarações de tipo determinam que valores uma função aceita e devolve. O sistema de tipos foi crescendo ao longo de muitas versões. Segundo o registo de alterações do manual, foram acrescentadas, entre outras, estas possibilidades:
| Versão | Novidade |
|---|---|
| 7.1.0 | tipos anuláveis (?int), void, iterable |
| 7.2.0 | object |
| 7.4.0 | propriedades de classe com tipo |
| 8.0.0 | tipos união (vários tipos permitidos numa só indicação), mixed, tipo de retorno static |
| 8.1.0 | tipos intersecção (A&B), tipo de retorno never |
| 8.2.0 | tipos DNF, tipo literal true, null e false como tipos autónomos |
| 8.3.0 | constantes de classe, interface, trait e enum com tipo |
DNF significa forma normal disjuntiva e permite combinações como (A&B)|null. Quem planeia versões do PHP vê também, nesta tabela, que recursos da linguagem uma aplicação pressupõe.
strict_types: conversão ou TypeError
Sem mais indicações, o PHP trabalha em modo de conversão. Uma função com parâmetros int aceita então também 1.5 e faz dele 1; desde o PHP 8.1, esta conversão com perda está marcada como obsoleta. Com declare(strict_types=1) no início do ficheiro, o PHP lança em vez disso um TypeError.
<?php
declare(strict_types=1);
function summe(int $a, int $b): int
{
return $a + $b;
}
echo summe(1, 2); // 3
echo summe(1.5, 2.5); // TypeError, em vez de silenciosamente 3
Há duas subtilezas importantes. Em primeiro lugar, o strict_types aplica-se às chamadas feitas a partir do ficheiro em que consta, não às funções aí definidas. Se um ficheiro sem strict_types chamar a mesma função, há conversão. Em segundo lugar, um número inteiro onde se espera um número de vírgula flutuante é permitido também no modo estrito.
Comparações laxas e estritas
O operador == compara depois de uma conversão de tipos, o === compara valor e tipo sem conversão. O manual recomenda, na maioria dos casos, === e !==, porque as regras de conversão nem sempre são óbvias.
<?php
var_dump(0 == "a"); // PHP 7: true, PHP 8: false
var_dump("1" == "01"); // true, ambas são cadeias de caracteres numéricas
var_dump("1" === "01");// false, mesmo tipo, mas cadeia de caracteres diferente
var_dump(1 == true); // true
var_dump(1 === true); // false
Com o PHP 8.0, as comparações entre números e cadeias de caracteres não numéricas tornaram-se mais razoáveis. As aplicações mais antigas podem comportar-se de forma diferente depois da atualização, por exemplo em blocos switch. A expressão match, introduzida também com o PHP 8.0, compara sempre de forma estrita. Como as comparações laxas levam a vulnerabilidades, por exemplo em verificações de tokens ou de palavras-passe, descreve-o o artigo Type juggling: comparações laxas como risco de segurança.
Tipos, atualizações e PHP2Shell
Um sistema de tipos rigoroso torna o código da aplicação mais robusto, mas não protege contra erros no próprio interpretador. As vulnerabilidades PHP2Shell CVE-2026-109618 e CVE-2026-109619 estão na gestão de memória e de pedidos do PHP. Estão corrigidas no PHP 8.5.12, 8.4.27, 8.3.36 e 8.2.35; depois, todos os processos PHP têm de ser reiniciados.
O sistema de tipos desempenha, ainda assim, um papel, e é na atualização. As aplicações que ainda estão presas ao PHP 8.1 ou anterior já não recebem atualizações oficiais do projeto PHP. O código bem tipado é muito mais fácil de elevar a uma versão suportada, porque as ferramentas encontram incompatibilidades cedo. Nos projetos mais antigos, ajuda a nossa migração para uma versão do PHP suportada.
Ative o strict_types de forma gradual, em ficheiros novos e revistos. Assim, a segurança de tipos cresce sem que o código antigo deixe de funcionar de uma só vez.
Como ajuda concretamente a PHP SOS?
- Verificamos que versão do PHP a sua aplicação exige no mínimo e comparamos com as versões corrigidas.
- Executamos a análise estática sobre o código e assinalamos os pontos com comparações laxas em verificações relevantes para a segurança.
- Planeamos as atualizações de modo que as regras de comparação alteradas sejam testadas antes.
- Aplicamos a atualização do PHP, reiniciamos todos os workers e documentamos o estado.
Perguntas frequentes
O PHP tem tipagem forte ou fraca?
O PHP tem tipagem dinâmica: o tipo de uma variável só é conhecido em tempo de execução. Sem strict_types, o PHP converte valores quando necessário. Com declarações de tipo e strict_types, o código pode, no entanto, tornar-se muito rigoroso.
O que faz declare(strict_types=1)?
Desativa, nas chamadas feitas a partir do respetivo ficheiro, a conversão automática de valores escalares. Se um valor não corresponder ao tipo declarado, o PHP lança um TypeError. A única exceção é um número inteiro onde se espera um número de vírgula flutuante.
Porque é que 0 == «a» é falso no PHP 8 e verdadeiro no PHP 7?
Até ao PHP 7, uma cadeia de caracteres não numérica era convertida num número na comparação com um número, e «a» passava a 0. Desde o PHP 8.0, o PHP deixou de comparar numericamente neste caso e o resultado é false.
Os tipos protegem contra vulnerabilidades do próprio PHP?
Não. Os tipos evitam erros no código da sua aplicação. As vulnerabilidades no interpretador, como o PHP2Shell, só se fecham com uma atualização do PHP. As funcionalidades de tipos modernas pressupõem, porém, versões atuais do PHP e são por isso uma boa ocasião para atualizar.