Manejo de Errores y Excepciones en PHP

try / catch / finally, excepciones propias y errores nativos de PHP 8

🎯 Demo en Vivo

Resultado de dividirSeguro():

Prueba valores en el formulario →

Prueba distintos valores

📖 Explicación del Código

Código completo

class NumeroInvalidoException extends Exception {}

function dividirSeguro(float $dividendo, float $divisor): float {
    if ($divisor < 0) {
        throw new NumeroInvalidoException(t('El divisor no puede ser negativo') . " (\$divisor).");
    }
    return $dividendo / $divisor; // PHP 8 lanza DivisionByZeroError si \$divisor es 0}

try {
    $resultado = dividirSeguro($dividendo, $divisor);
    echo t('Resultado:') . " \$resultado";
} catch (DivisionByZeroError $e) {
    echo t('No se puede dividir por cero:') . " " . \$e->getMessage();
} catch (NumeroInvalidoException $e) {
    echo t('Dato inválido:') . " " . \$e->getMessage();
} catch (Throwable $e) {
    echo t('Error inesperado:') . " " . \$e->getMessage();
} finally {
    echo t('Esto se ejecuta siempre.');
}

📝 Excepción personalizada

¿Qué hace? NumeroInvalidoException extends Exception crea un tipo de error propio, con nombre descriptivo, que puedes capturar de forma independiente del resto.

📝 Orden de los catch

¿Por qué importa? PHP evalúa los bloques catch en orden y usa el primero que coincida con el tipo lanzado.. Por eso los más específicos (DivisionByZeroError, NumeroInvalidoException) van antes que el genérico Throwable.

💡 Concepto: Error vs Exception

Desde PHP 7, los errores fatales (como DivisionByZeroError) también son objetos capturables.. Throwable es la interfaz común a Error y Exception, así que un catch (Throwable $e) atrapa cualquier cosa que se les escape a los anteriores.

📝 El bloque finally

¿Qué hace? Se ejecuta siempre, haya habido excepción o no. Ideal para liberar recursos (cerrar una conexión, un archivo, etc.).

🎯 Conceptos Clave

try / catch / finally

  • try: código que puede fallar
  • catch: qué hacer si falla
  • finally: siempre se ejecuta

Excepciones propias

  • extends Exception
  • Dan nombre y contexto al error

Throwable

  • Interfaz común de Error y Exception
  • Red de seguridad final en el catch

💪 Ejercicio Práctico

Amplía el manejo de errores

  1. Crea una excepción NumeroDemasiadoGrandeException que se lance si el dividendo supera 1.000.000.
  2. Añade un método getMensajeUsuario() a NumeroInvalidoException que devuelva un texto amigable distinto al técnico.
  3. Registra un set_exception_handler() global que muestre una página de error genérica ante cualquier excepción no capturada.

Solución 1

class NumeroDemasiadoGrandeException extends Exception {}

if ($dividendo > 1000000) {
    throw new NumeroDemasiadoGrandeException(t('Dividendo demasiado grande:') . " $dividendo");
}

Solución 2

class NumeroInvalidoException extends Exception {
    public function getMensajeUsuario(): string {
        return t('Revisa los números introducidos, hay algo incorrecto.');
    }
}

Solución 3

set_exception_handler(function (Throwable $e) {
    error_log($e->getMessage());
    echo t('Ha ocurrido un error inesperado. Inténtalo más tarde.');
});