Manejo de errores en PHP 7. Clase Error


Manejo de errores en PHP 7. Clase Error

Repasamos la clase Error de PHP y su jerarquía. Revisamos algunos ejemplos básicos y vemos un par de formas de manejar estos errores.



Configuración inicial

Trabajaremos en este articulo con la siguiente configuración
 /* Configuración para index.php */
declare(strict_types=1);
ini_set('error_reporting', 'E_ALL');
ini_set('display_errors', '1');
Ademas en el articulo anterior comentamos que cuando lanzamos un objeto Throwable (por ahora solo veremos solo errores) podían ocurrir una de tres cosas.
  • Encuentre un bloque catch() que soporte el error
  • Exista un manejador de excepciones establecido con set_error_handler()
  • O en ultimo caso, el error se convertirá en un error fatal
En los dos primeros casos el error se mostrara pero el script continuara la ejecución normal, en el tercer caso el script terminara su ejecución mostrando un feo mensaje.

Tipos de errores

Se sabe que Error es la clase base para todos los errores de PHP internos (Desde PHP 7). Así en los tres casos mencionados arriba, sera tarea del programador arreglarlos pues este tipo de errores no deben aparecer en tiempo de ejecución.
Árbol de jerarquías de errores en PHP
Árbol de jerarquías de errores en PHP
De esta clase encontramos las siguientes clases hijas:
ArithmeticError. Es lanzado cuando ocurre un error durante la realización de operaciones matemáticas.
DivisionByZeroError. Se lanza al intentar dividir un número por cero.
AssertionError. Se lanza cuando falla una afirmación realizada mediante assert().
ParseError. Se lanza cuando ocurre un error al analizar código de PHP.
TypeError. Para mas claridad sobre TypeError mejor leamos que nos dice el mismo PHP

Existen tres escenarios donde de podría lanzar un TypeError. El primero es donde el tipo de argumento pasado a una función no coincide con su correspondiente tipo de parámetro declarado. El segundo es donde un valor devuelto desde una función no coincide con el tipo de devolución declarado en la función. El tercero es donde se proporciona un número inválido de argumentos a una función interna de PHP (solamente en modo estricto).:

TypeError - PHP

ArgumentCountError, es lanzado cuando el numero de parámetros que espera un método o función es menor a los enviados.
Los errores tipo AssertionError están relacionadas con descubrir errores lógicos durante el desarrollo de una aplicación. Esto es claramente diferente al manejo de errores y se recomienda no activar esta configuración a menos que requieras realizar pruebas unitarias.
Los errores mas comunes están relacionados con ArithmeticError, ParseError y TypeError y haremos algunos ejemplos con ellos.

Primeros ejemplos

Tendremos una clase llamada Aplicacion para ir observando la continuidad del script, ademas de un método area() para la prueba de los errores TypeError.
/* Clase Aplicacion */
namespace Blockpc\Clases;
class Aplicacion {
public function __construct() {
echo "Aplicacion constructor...<br>";
}
public function area(int $ancho, int $alto): string {
$area = $ancho * $alto;
return "El área es {$area} unidades<br>";
}
public function __destruct() {
echo "... Aplicacion destructor.<br>";
}
}
Usaremos un bloque try... catch() para ir probando los ejemplos:
 /* index.php */
try {
$aplicacion = new Aplicacion;
/*
* Acá irán nuestros ejemplos con errores
*/
} catch(Throwable $e) {
echo '<pre><b>Clase</b>: '; print_r(get_class($e)); echo '</br>';
echo '<b>Linea</b>: '; print_r($e->getLine()); echo '</br>';
echo '<b>Archivo</b>: '; print_r($e->getFile()); echo '</br>';
echo '<b>Mensaje</b>: '; print_r($e->getMessage()); echo '</pre>';
exit;
}
La idea del objeto $aplicacion es que podamos leer tanto su constructor como su destructor mientras ejecutamos los ejemplos y atrapamos los errores. Un error fatal evitaría leer la destrucción del objeto.
ArithmeticError Entre las llaves del bloque try{...} en nuestro index.php pondremos un ejemplo aritmético que causa un error:
/* ArithmeticError */
echo "<h2>ArithmeticError</h2>";
//$value = 1 << -1; // Error
//intdiv(PHP_INT_MIN, -1); // Error
ParseError Usaremos como ejemplo require e include por ser los mas comunes.
/* ParseError */
echo "<h2>ParseError</h2>";
//require 'archivo-con-parse-error.php'; // Error
//include 'archivo-con-parse-error.php'; // Error
/* Si cargas un archivo que no existe, ocurrirá un error fatal */
//require 'archivo-que-no-existe.php'; // Error fatal
//include 'archivo-que-no-existe.php'; // Error fatal
/* Los errores fatales se manejan con set_error_handler() */
TypeError Usamos la función area() de la clase Aplicacion para señalar los errores.
/* TypeError */
echo "<h2>TypeError</h2>";
echo $aplicacion->area(3, 5); /* Correcto */
/* Error, con strict_types activado.
* Con strict_types desactivado se promociona el '3' a entero */
//echo $aplicacion->area('3', 5);
/* Error, con strict_types activado o desactivado
* No se promociona el 'tres' a entero, ocurrirá un error */
//echo $aplicacion->area('tres', 5);
/* Error relacionado a ArgumentCountError */
//echo $aplicacion->area(4); /* Error */
//echo $aplicacion->area(4, 5, 6); /* Correcto */
En el archivo del código fuente (que estará al final del articulo, como siempre) aparecen las lineas comentadas.

Clase MiError

La idea de esta clase, tal como vimos en el articulo anterior es controlar los diferentes errores en nuestra aplicación durante la fase de desarrollo. Destaco que existen otras maneras de hacer lo mismo, esta para mi es la más sencilla.
/* MiError.php */
namespace Blockpc\Errores;
class MiError extends \Error implements MiThrowable {
public function __construct($message = "", $code = 0, \Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
/* implementamos la función requerida por la interface */
public function metodoPersonalizado() {
return "Este es el método personalizado de MiError.<br>";
}
}
Ahora para que esta clase funcione, la agregamos al catch() de nuestro index.php. Ademas lanzamos un objeto de error MiError en el try{...}
/* index.php */
try {
$aplicacion = new Aplicacion;
/*
* Acá irán nuestros ejemplos con errores
*/
echo "<h2>Clase MiError</h2>";
throw new MiError('Un error personalizado');
} catch(MiError | Throwable $e) {
echo '<pre><b>Clase</b>: '; print_r(get_class($e)); echo '</br>';
echo '<b>Linea</b>: '; print_r($e->getLine()); echo '</br>';
echo '<b>Archivo</b>: '; print_r($e->getFile()); echo '</br>';
echo '<b>Mensaje</b>: '; print_r($e->getMessage()); echo '</pre>';
exit;
}

Vista de nuestra clase MiError en la jerarquía de Error en PHP
Vista de nuestra clase MiError en la jerarquía de Error en PHP
El objeto MiError es capturado y el script continua. Recordemos que la clase MiError implementa Throwable. Así, los primeros errores mencionados (todos los Throwable) no serán objetos MiError lo que si pasa al revés. Puedes seguir el sentido de las flechas en la figura.
Si quisiéramos usar el método metodoPersonalizado de la clase MiError deberíamos identificar el objeto de error dentro del catch().
/* index.php */
try {
$aplicacion = new Aplicacion;
/*
* Acá irán nuestros ejemplos con errores
*/
echo "<h2>Clase MiError</h2>";
throw new MiError('Un error personalizado');
} catch(MiError | Throwable $e) {
/* Se atrapa el error pero el script continua */
if ( $e instanceof MiError ) {
$e->metodoPersonalizado();
} else { // sino es un objeto Throwable
echo '<pre><b>Clase</b>: '; print_r(get_class($e)); echo '</br>';
echo '<b>Linea</b>: '; print_r($e->getLine()); echo '</br>';
echo '<b>Archivo</b>: '; print_r($e->getFile()); echo '</br>';
echo '<b>Mensaje</b>: '; print_r($e->getMessage()); echo '</pre>';
}
exit;
}
Es necesario hacer esto? Si, siempre que quieras usar el método metodoPersonalizado, por ejemplo para enviar un correo informándote del error. Por ahora este método solo mostrara información sobre el error.
public function metodoPersonalizado() {
// implementamos el código de error personalizado
echo '<pre><b>Error personalizado:</b><br>';
echo '<b>Clase</b>: '; print_r(get_class($e)); echo '</br>';
echo '<b>Linea</b>: '; print_r($e->getLine()); echo '</br>';
echo '<b>Archivo</b>: '; print_r($e->getFile()); echo '</br>';
echo '<b>Mensaje</b>: '; print_r($e->getMessage()); echo '</pre>';
}


Probando nuestra clase

Para probar nuestra clase MiError crearemos una clase Iniciar que por medio de un método ejecutarError()() emita un error.
/* Clase Iniciar */
namespace Blockpc\Clases;
use Blockpc\Errores\MiError;
class Iniciar {
public function __construct() {
echo "Iniciar constructor...<br>";
}
public function ejecutarError() {
throw new MiError("Error en la clase Iniciar");
}
public function __destruct() {
echo "... Iniciar destructor.<br>";
}
}
Entonces agregamos a nuestro archivo index.php
/* index.php */
echo "<h2>Clase Iniciar</h2>";
$iniciar = new Iniciar;
$iniciar->ejecutarError();
Nuestro código atrapara el error lanzado por el método ejecutarError() en el catch() pues se cumple que este es un objeto de MiError. Aun con esto, debes notar que un objeto MiError es genérico y que si bien es utilizable, no es especifico en lo referente a la clase donde se emite el error.

Una clara ventaja

Una de las ventajas de todo esto es que podemos crear un tipo de error especifico para cada clase de nuestra aplicación y así podemos informarnos mucho mejor de lo que sucede.
Podemos crear una clase llamada IniciarError que extienda de MiError, que por el nombre entendemos que hace mención a la clase Iniciar
/* IniciarError.php */
namespace Blockpc\Errores;
class IniciarError extends MiError {}
Luego en el método ejecutarError() de la clase Iniciar cambiamos el objeto de error.
//* Clase Iniciar */
public function ejecutarError() {
//throw new MiError("Error en la clase Iniciar");
throw new IniciarError("Error en la clase Iniciar");
}
Y la salida en pantalla seria mucho mas especifica con solo ese cambio.

Ultimas consideraciones

La clase Error de PHP se relaciona básicamente con errores durante el proceso de desarrollo que debemos arreglar para un correcto funcionamiento de una aplicación. Siguiendo esta lógica podemos decir que la clase Exception esta relacionada con errores que ocurren en tiempo de ejecución y que son aplicables al control que hace la aplicación respecto de los datos que proporciona un usuario.
En el próximo articulo haremos algo muy parecido a lo de hoy pero con la clase Exception.

El código fuente lo puedes descargar desde acá

Saludos y nos leemos en el próximo articulo.

Etiquetas php errores

Ultima actualización Lunes 11 de Junio, 2018




Agregar Comentario