Lanzables (Throwables) en PHP 7

Las excepciones en PHP no son un concepto nuevo. Han existido desde que se lanzó PHP 5. Sin embargo, no abarcaban todo el manejo de errores de PHP porque los errores no se consideraban excepciones. PHP, en ese momento, tenía sistemas de manejo de dos errores. Esto dificultaba el tratamiento, ya que los errores tradicionales no se podían detectar a través de los bloques de  excepciones try … catch. Ciertos trucos eran posibles, donde uno podría haber usado la función set_error_handler () para establecer una función de manejo de errores definida por el usuario, básicamente escuchando errores y convirtiéndolos en excepciones.

Veamos el siguiente ejemplo:

<?php
class Mailer
{
private $transport;
public function __construct(Transport $transport)
{
$this->transport = $transport;
}
}
$transport = new stdClass();
try {
$mailer = new Mailer($transport);
} catch (\Exception $e) {
echo 'Caught!';
} finally {
echo 'Cleanup!';
}

PHP 5 no podría detectar esto, y en su lugar arroja un error fatal capturable, como se muestra aquí:

Catchable fatal error: Argument 1 passed to Mailer::__construct() must be
an instance of Transport, instance of stdClass given, called in /index.php
on line 18 and defined in /index.php on line 6.

Al agregar la implementación de set_error_handler () antes de este código, de la siguiente manera, podríamos convertir ese error fatal en una excepción:

set_error_handler(function ($errno, $errstr) {
throw new \Exception($errstr, $errno);
});

Con el código anterior en su lugar, los bloques try…catch…finally ahora se activarían según lo previsto. Sin embargo, hubo tipos de errores que no se pudieron detectar con set_error_handler, como E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING y la mayoría de E_STRICT generados en el archivo donde se llama a set_error_handler.

El lanzamiento de PHP 7 mejoró el sistema general de manejo de errores al introducir la interfaz Throwable y mover los errores y excepciones bajo su paraguas. Ahora es la interfaz base para cualquier objeto que se pueda lanzar a través de una instrucción throw. Si bien no podemos extender directamente, podemos extender las clases \Exception y \Error. Mientras \Exception es la clase base para todas las excepciones PHP y de usuario, \Error es la clase base para todos los errores internos de PHP.

Ahora podríamos reescribir fácilmente nuestro intento anterior … capturar … finalmente bloquear en uno de los siguientes:

<?php
// Case 1
try {
$mailer = new Mailer($transport);
} catch (\Throwable $e) {
echo ‘Caught!’;
} finally {
echo ‘Cleanup!’;
}

// Case 2
try {
$mailer = new Mailer($transport);
} catch (\Error $e) {
echo ‘Caught!’;
} finally {
echo ‘Cleanup!’;
}

Observe el uso de \Throwable en el primer bloque catch de ejemplo. Aunque no podemos extenderlo, podemos usarlo como una forma abreviada para capturar tanto \Error como \Exception en una sola instrucción catch.

La implementación de \Throwable brinda una alineación muy necesaria entre errores y excepciones, lo que facilita su razonamiento.

Comparte