Las excepciones son el mecanismo de PHP para comunicar y gestionar errores de forma estructurada. Con throw señalizas un error, con try/catch lo capturas y con finally ejecutas código que siempre debe correr, haya o no excepción. Entender la jerarquía Throwable es clave para capturar exactamente lo que necesitas.
throw, try y catch básicos
<?php
function dividir(float $a, float $b): float
{
if ($b === 0.0) {
throw new InvalidArgumentException('No se puede dividir por cero');
}
return $a / $b;
}
try {
echo dividir(10, 2); // 5
echo dividir(10, 0); // lanza excepción
} catch (InvalidArgumentException $e) {
echo 'Error de argumento: ' . $e->getMessage();
}
// 5Error de argumento: No se puede dividir por cero
?>
El bloque finally
finally se ejecuta siempre, tanto si hubo excepción como si no. Es útil para liberar recursos:
<?php
function procesarFichero(string $ruta): string
{
$handle = fopen($ruta, 'r');
if ($handle === false) {
throw new RuntimeException("No se puede abrir: $ruta");
}
try {
$contenido = fread($handle, filesize($ruta));
if ($contenido === false) {
throw new RuntimeException("Error al leer el fichero");
}
return $contenido;
} finally {
fclose($handle); // siempre se ejecuta, aunque haya excepción
echo "Fichero cerradon";
}
}
try {
$texto = procesarFichero('/etc/hostname');
echo $texto;
} catch (RuntimeException $e) {
echo 'Error: ' . $e->getMessage();
}
?>
La jerarquía Throwable
Throwable
??? Error ? errores internos del motor de PHP
? ??? TypeError
? ??? ValueError
? ??? ArithmeticError
? ? ??? DivisionByZeroError
? ??? ParseError
? ??? ...
??? Exception ? errores de la lógica de aplicación
??? LogicException
? ??? BadMethodCallException
? ??? InvalidArgumentException
? ??? OutOfRangeException
??? RuntimeException
??? OutOfBoundsException
??? OverflowException
??? ...
Capturar Error vs Exception
<?php
// Error del motor: TypeError al pasar tipo incorrecto
function sumar(int $a, int $b): int
{
return $a + $b;
}
try {
// En modo strict, esto lanza TypeError
echo sumar(1, '2');
} catch (TypeError $e) {
echo 'TypeError: ' . $e->getMessage();
}
// Capturar ambos con Throwable (solo cuando realmente necesitas capturar todo)
try {
$x = 1 / 0;
} catch (DivisionByZeroError $e) {
echo 'División por cero: ' . $e->getMessage();
} catch (Error $e) {
echo 'Error del motor: ' . $e->getMessage();
} catch (Exception $e) {
echo 'Excepción: ' . $e->getMessage();
}
?>
Encadenar excepciones con $previous
<?php
function conectarBD(string $dsn): PDO
{
try {
return new PDO($dsn);
} catch (PDOException $e) {
// Envuelve la excepción de PDO en una propia, manteniendo el contexto
throw new RuntimeException(
'No se pudo conectar a la base de datos',
0,
$e // ? excepción anterior
);
}
}
try {
$pdo = conectarBD('mysql:host=noexiste;dbname=test');
} catch (RuntimeException $e) {
echo $e->getMessage() . "n";
echo 'Causa original: ' . $e->getPrevious()->getMessage();
}
?>
Capturar múltiples tipos en un catch
<?php
function procesarPago(float $cantidad): void
{
if ($cantidad <= 0) {
throw new InvalidArgumentException('Cantidad inválida');
}
if ($cantidad > 10000) {
throw new OverflowException('Cantidad excede el límite');
}
// procesar...
}
try {
procesarPago(-50);
} catch (InvalidArgumentException | OverflowException $e) {
echo 'Error de validación: ' . $e->getMessage();
}
?>
La documentación oficial de excepciones en PHP y la interfaz Throwable detallan todos los métodos disponibles en los objetos de excepción y las reglas de propagación por la pila de llamadas.
