PHP convierte tipos automáticamente cuando se lo permites: suma un string numérico a un entero, compara cosas que no son iguales y nadie dice nada. Esto se llama type juggling y puede ser el origen de bugs difíciles de rastrear. La directiva declare(strict_types=1) cambia ese comportamiento en el fichero donde la escribes: a partir de ese momento PHP exige que el tipo del argumento coincida exactamente con la firma de la función, o lanza un TypeError.
Qué hace declare(strict_types=1)
Puesta en la primera línea de un fichero PHP, antes de cualquier otro código, activa el modo estricto solo para ese fichero. Las llamadas que haga ese fichero a funciones con tipos declarados deben respetar exactamente esos tipos; PHP no intentará coercionar.
<?php
declare(strict_types=1);
function sumar(int $a, int $b): int {
return $a + $b;
}
echo sumar(3, 4); // 7 correcto
echo sumar("3", 4); // TypeError: Argument #1 must be of type int, string given
Sin strict_types, sumar("3", 4) devuelve 7 silenciosamente porque PHP convierte "3" a 3.
Type juggling: los casos que más sorprenden
El type juggling de PHP sigue reglas que pueden resultar contraintuitivas:
<?php
// Comparación laxa (==)
var_dump(0 == "foo"); // true en PHP 7, false en PHP 8
var_dump("1" == "01"); // true
var_dump("100" == "1e2"); // true (ambos son 100 en notación científica)
var_dump(0 == false); // true
var_dump("" == false); // true
var_dump("" == null); // true
// Conversión implícita de string a entero
$total = 0;
$total += "42 artículos"; // $total = 42; PHP toma el prefijo numérico
$total += "artículos: 5"; // $total = 42; "artículos: 5" ? 0
Antes y después: cuatro ejemplos reales
Ejemplo 1: parseo de un parámetro de ruta
<?php
// SIN strict_types silenciosamente acepta el string
function getUser(int $id): string {
return "Usuario $id";
}
echo getUser("5abc"); // "Usuario 5" PHP convierte "5abc" a 5, pierde "abc"
// CON strict_types=1 TypeError inmediato
declare(strict_types=1);
echo getUser("5abc"); // Fatal error: TypeError
Ejemplo 2: función con float y string numérico
<?php
declare(strict_types=1);
function descuento(float $precio, float $porcentaje): float {
return $precio * (1 - $porcentaje / 100);
}
// OK: los literales numéricos siempre son compatibles
echo descuento(100.0, 20.0); // 80.0
// Error: un string "20.0" no es float en modo estricto
echo descuento(100.0, "20.0"); // TypeError
Ejemplo 3: valores booleanos disfrazados de enteros
<?php
declare(strict_types=1);
function activar(bool $estado): string {
return $estado ? 'activo' : 'inactivo';
}
echo activar(true); // activo
echo activar(1); // TypeError en strict mode (1 no es bool)
echo activar(0); // TypeError en strict mode (0 no es bool)
Ejemplo 4: retorno de tipo incorrecto
<?php
declare(strict_types=1);
function contarPalabras(string $texto): int {
return str_word_count($texto); // devuelve int, correcto
}
// str_word_count() SÍ devuelve int, por lo que funciona
echo contarPalabras("hola mundo"); // 2
Reglas importantes
- El modo estricto afecta solo al fichero que lo declara, no a los ficheros que llama ni a los que lo incluyen.
- Las funciones internas de PHP (como
strlen(),array_map()) son más tolerantes con la coerción incluso en modo estricto. - Los literales enteros y flotantes del propio código fuente siempre son del tipo correcto; el problema está en los datos externos (strings de formularios, APIs ).
- Usar
strict_types=1no reemplaza la validación de entradas: sigue siendo necesario limpiar y validar los datos antes de pasarlos a tus funciones.
Cuándo activarlo
Activar strict_types=1 en todos los ficheros nuevos de un proyecto es una buena práctica. Los errores que antes fallaban silenciosamente aparecerán en desarrollo (con un TypeError claro) y no en producción con datos incorrectos. En código legado, actívalo fichero a fichero y corrige los TypeError que surjan: cada uno te muestra un punto donde antes perdías información de tipo sin darte cuenta.
