throw
En PHP, la palabra clave "throw" se usa para lanzar una excepción. Las excepciones permiten manejar errores y condiciones inesperadas en tu código.
La palabra clave throw en PHP
La palabra clave throw detiene la ejecución normal en el punto donde se ejecuta y lanza una excepción — un objeto que señala que algo salió mal. El control salta inmediatamente fuera de la función actual y sube por la pila de llamadas hasta encontrar un bloque catch coincidente. Si ningún catch coincide, PHP detiene el script con un error fatal.
Esta página cubre la sintaxis de throw, cuándo usarlo en lugar de devolver un valor de error, cómo lanzar excepciones integradas y personalizadas, cómo relanzar y encadenar excepciones, y la característica de PHP 8 que permite usar throw como expresión. Para una visión más amplia, consulta Excepciones en PHP y el flujo try/catch/finally.
Sintaxis
throw new Exception("Error message here");A throw se le debe pasar un valor que sea una instancia de Throwable — en la práctica una Exception (o una de sus subclases) o un Error. La cadena pasada al constructor se convierte en el mensaje de la excepción, que se puede leer posteriormente con getMessage().
Como una excepción lanzada desenreda la pila, cualquier código después de throw en el mismo bloque nunca se ejecuta:
throw new Exception("stop here");
echo "this line is unreachable"; // never executes¿Por qué usar throw en lugar de devolver un error?
Devolver un valor especial (como false o -1) para señalar un fallo obliga a cada llamador a recordar verificarlo, y el significado del valor es fácil de perder. throw hace que el fallo sea imposible de ignorar: la excepción se propaga automáticamente hasta que algo la maneje, y lleva consigo un mensaje, un código, un seguimiento de la pila y el archivo y línea donde ocurrió.
Usa throw para condiciones excepcionales de las que la función actual no puede recuperarse sensatamente — argumentos inválidos, una conexión a base de datos fallida, un archivo requerido que no existe — y deja que un llamador de nivel superior decida qué hacer.
Un ejemplo básico
Aquí una función divide() lanza una excepción al intentar dividir por cero, y el llamador la captura:
<?php
function divide(int $numerator, int $denominator): float
{
if ($denominator === 0) {
throw new InvalidArgumentException("Cannot divide by zero.");
}
return $numerator / $denominator;
}
try {
echo divide(10, 2), PHP_EOL; // 5
echo divide(10, 0), PHP_EOL; // throws before printing
} catch (InvalidArgumentException $e) {
echo "Caught: " . $e->getMessage() . PHP_EOL;
}Salida:
5
Caught: Cannot divide by zero.La primera llamada tiene éxito e imprime 5. La segunda lanza una excepción, por lo que su echo nunca se ejecuta y el control salta directamente al bloque catch.
Lanzar una excepción personalizada
Extender Exception permite dar a cada tipo de error su propio nombre, de modo que los llamadores puedan capturar exactamente los fallos que les interesan e ignorar el resto:
<?php
class InsufficientFundsException extends Exception {}
function withdraw(float $balance, float $amount): float
{
if ($amount > $balance) {
throw new InsufficientFundsException(
"Cannot withdraw $amount; balance is only $balance."
);
}
return $balance - $amount;
}
try {
echo withdraw(100, 250), PHP_EOL;
} catch (InsufficientFundsException $e) {
echo "Declined: " . $e->getMessage() . PHP_EOL;
}Salida:
Declined: Cannot withdraw 250; balance is only 100.Consulta Clases de excepción personalizadas para más información sobre cómo extender Exception.
Mensaje, código y excepción previa de la excepción
El constructor de Exception acepta tres argumentos — message, code y una excepción previous. El tercero te permite envolver un error de bajo nivel en uno más significativo sin perder la causa original (esto se llama encadenamiento de excepciones):
<?php
try {
try {
throw new RuntimeException("Disk read failed", 13);
} catch (RuntimeException $low) {
// Re-throw a higher-level exception, keeping the original as the cause.
throw new Exception("Could not load config", 0, $low);
}
} catch (Exception $e) {
echo $e->getMessage() . PHP_EOL; // Could not load config
echo "Caused by: " . $e->getPrevious()->getMessage() . PHP_EOL; // Disk read failed
echo "Original code: " . $e->getPrevious()->getCode() . PHP_EOL; // 13
}Salida:
Could not load config
Caused by: Disk read failed
Original code: 13Relanzar en un bloque catch
No es necesario manejar completamente una excepción donde se captura. Un bloque catch puede realizar algún trabajo (registrarla, añadir contexto) y luego lanzar throw nuevamente para que un manejador externo termine el trabajo:
<?php
function loadUser(int $id): array
{
try {
throw new RuntimeException("Database is down");
} catch (RuntimeException $e) {
error_log("loadUser($id) failed: " . $e->getMessage());
throw $e; // pass it on
}
}
try {
loadUser(7);
} catch (RuntimeException $e) {
echo "Handled at top level: " . $e->getMessage() . PHP_EOL;
}Salida:
Handled at top level: Database is downthrow como expresión (PHP 8+)
Desde PHP 8.0, throw es una expresión, no solo una sentencia, por lo que puedes usarlo en lugares que esperan un valor — como los operadores ?: y ?? o una función flecha:
<?php
function getConfig(array $config, string $key): string
{
// Throw inline when the key is missing.
return $config[$key] ?? throw new InvalidArgumentException("Missing key: $key");
}
echo getConfig(['env' => 'prod'], 'env'), PHP_EOL; // prod
try {
getConfig(['env' => 'prod'], 'region');
} catch (InvalidArgumentException $e) {
echo $e->getMessage() . PHP_EOL;
}Salida:
prod
Missing key: regionErrores comunes
- Lanzar sin un
try/catchen ningún punto de la pila. Una excepción no capturada se convierte en un error fatal y detiene el script. Captúrala siempre en algún lugar, o registra un manejador alternativo conset_exception_handler(). - Lanzar una cadena o un array.
throwrequiere un objeto que implementeThrowable;throw "oops";es un error de sintaxis. - Silenciar excepciones. Un bloque
catchvacío oculta errores. Como mínimo registra el mensaje o vuelve a lanzar la excepción. - Usar excepciones para el flujo de control ordinario. Lanzar en cada rama esperada (por ejemplo, "usuario no encontrado" durante una búsqueda rutinaria) es lento y confuso — reserva las excepciones para casos verdaderamente excepcionales.
Resumen
throwlanza unThrowabley desenreda inmediatamente la pila hasta elcatchcoincidente más cercano.- Prefiérelo sobre valores de retorno especiales para que los fallos no puedan ignorarse silenciosamente.
- Subclasifica
Exceptionpara crear tipos de error con nombre; pasa una excepciónpreviouspara encadenar causas. - Captura, añade contexto y vuelve a usar
throwpara que un manejador externo decida. - En PHP 8+,
throwfunciona como expresión dentro de??,?:y funciones flecha.
Continúa con el bloque try, el bloque catch y finally para ver el ciclo completo de manejo de excepciones.