Excepciones en PHP: throw, try/catch/finally y la jerarquía de Exception

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.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP