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 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 fallarcatch: qué hacer si fallafinally: siempre se ejecuta
Excepciones propias
extends Exception- Dan nombre y contexto al error
Throwable
- Interfaz común de
ErroryException - Red de seguridad final en el catch
💪 Ejercicio Práctico
Amplía el manejo de errores
- Crea una excepción
NumeroDemasiadoGrandeExceptionque se lance si el dividendo supera 1.000.000. - Añade un método
getMensajeUsuario()aNumeroInvalidoExceptionque devuelva un texto amigable distinto al técnico. - 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.');
});