Manejo de errores en PHP 7

Tener errores y excepciones como dos sistemas diferentes de manejo de errores introducen un cierto nivel de confusión entre los desarrolladores. Las versiones anteriores de PHP dificultaban razonar con E_ERROR ya que no se pudieron detectar con manejadores de errores personalizados. La versión PHP 7 trató de resolver esta confusión presentando la interfaz Throwable, que es resumido de la siguiente manera:

Throwable {
abstract public string getMessage (void)
abstract public int getCode (void)
abstract public string getFile (void)
abstract public int getLine (void)
abstract public array getTrace (void)
abstract public string getTraceAsString (void)
abstract public Throwable getPrevious (void)
abstract public string __toString (void)
}

La interfaz Throwable ahora es la interfaz base para Error, Excepción y cualquier otro objeto que se pueda lanzar a través de una instrucción throw. Los métodos definidos en esta interfaz son casi idénticos a los de Exception. Las clases PHP por sí mismas no pueden implementar la interfaz Throwable directamente o se extiende desde Error; solo pueden extender Exception, como se muestra en el siguiente ejemplo:

<?php
class Glitch extends \Error
{
}
try {
throw new Glitch('Glitch!');
}
catch (\Exception $e) {
echo 'Caught '.$e->getMessage();
}

El código anterior dará como resultado la siguiente salida:

PHP Fatal error: Uncaught Glitch: Glitch! in index.php:7
Stack trace:
0 {main}
thrown in /root/app/index.php on line 7

Lo que sucede aquí es que la clase Glitch está tratando de extender la clase Error, que no está permitida y da como resultado un error Fatal que nuestro try…catch no detecta:

<?php
class Flaw extends \Exception
{
}
try {
throw new Flaw('Flaw!);
}
catch (\Exception $e) {
echo 'Caught '.$e->getMessage();
}

El ejemplo anterior es un uso válido de PHP Throwable, mientras que nuestra clase Flaw personalizada extiende la clase Exception. Se activa el bloque catch, lo que da como resultado el siguiente mensaje de salida:

Caught Flaw!

La nueva jerarquía de excepciones en PHP 7 es la siguiente:

interface Throwable
| Error implements Throwable
| TypeError extends Error
| ParseError extends Error
| ArithmeticError extends Error
| DivisionByZeroError extends ArithmeticError
| AssertionError extends Error
| Exception implements Throwable
| …

El beneficio de la nueva interfaz Throwable es que ahora podemos capturar fácilmente los objetos de excepción y error en un solo bloque de captura, según el siguiente ejemplo:

<?php
try {
throw new ArithmeticError('Missing numbers!');
}
catch (Throwable $t) {
echo $t->getMessage();
}

AssertionError extiende Error, que a su vez implementa la interfaz Throwable. La firma del bloque catch anterior apunta a la interfaz Throwable, por lo que se capturará el ArithmeticError arrojado y la salida de los números que faltan.
Aunque nuestras clases no pueden implementar la interfaz Throwable, podemos definir la interfaz que la extiende. Tal interfaz solo puede ser implementada por una clase que extienda Excepción o Error, según el siguiente ejemplo:

<?php
interface MyThrowable extends Throwable
{
//…
}
class MyException extends Exception implements MyThrowable
{
//…
}
throw new MyException();

Si bien puede no ser una práctica común, este enfoque podría ser útil con interfaces específicas de paquetes.

Comparte