Manejo de errores en PHP 7. Algo de teoría


Manejo de errores en PHP 7. Algo de teoría

Revisamos algunos conceptos básicos para manejar los errores en PHP durante el desarrollo de una aplicación web, las clases asociadas y algunos ejemplos.



Por muy buenos escritores de código que seamos, siempre estaremos propensos a cometer errores. Estos errores se pueden dar en tiempo de desarrollo o en tiempo de ejecución (o producción). Pueden estar relacionados al core de PHP, al sistema que estamos construyendo o emitidos directamente por nosotros.
Es deber del programador reconocer estos errores cuando ocurran y saber como depurar los mismos.

Algo de historia

Antes de PHP 7 la clase Error y la clase Exception se encargaban de controlar los diferentes errores y excepciones en una aplicación.
Los errores están relacionados al lenguaje PHP, mientras que las excepciones son generadas por el programador para llevar un control mas efectivo durante la ejecución de la aplicación.
Sin embargo bajo ciertas condiciones como exceder el limite de memoria o requerir archivos que no existen, entre otras, estas causaban errores fatales y detenían la ejecución del script.
PHP 7 mejora el tratamiento de los errores haciendo que los famosos errores fatales se puedan controlar pues ahora se convierten en una excepción del tipo Error. Para ello incorpora la interface Throwable que es implementada por las clases Error y Exception.

Pasos previos

Para controlar los errores en nuestra aplicación podemos configurar los mismos en un archivo de configuración. Así para el proceso de desarrollo tendremos:
 /* Configuración en tiempo de desarrollo */
init_set('error_reporting', E_ALL | E_STRICT);
init_set('display_errors', 1);
/* Con strict_types activado */
declare(strict_types=1);
ini_set('error_reporting', 'E_ALL | E_STRICT');
ini_set('display_errors', '1');
Y para cuando estemos en producción tendremos:
 /* Configuración en producción */
init_set('error_reporting', E_ALL | E_STRICT);
init_set('display_errors', 0);
/* Con strict_types activado */
declare(strict_types=1);
ini_set('error_reporting', 'E_ALL | E_STRICT');
ini_set('display_errors', '0');

Aunque display_errors puede ser establecido en tiempo de ejecución (con ini_set()), no tendrá ningún efecto si el script tiene errores fatales. Esto es debido a que la acción deseada en tiempo de ejecución no se ejecuta.:

Configuración en tiempo de ejecución. PHP


Generando errores

Los errores son lanzados por medio de condiciones internas en PHP. Una lista de los tipos de errores la puedes encontrar acá.
Los errores se pueden lanzar mediante un throw y capturarlos en un bloque catch().
/* Lanzando un error */
try {
throw new Error('esta es un error');
} catch(Error $e) {
echo $e->getMessage();
}
Ademas tenemos a set_error_handler() para definir nuestra propia función para manejar errores personalizados y así poder mejorar el detalle de información relacionada con estos.

Generando excepciones

Las excepciones son lanzadas por condiciones externas a PHP por medio de throw y capturados en un bloque catch().
/* Lanzando una excepción */
try {
throw new Exception('esta es una excepción');
} catch(Exception $e) {
echo $e->getMessage();
}
También esta set_exception_handler() para definir una función propia para nuestras excepciones y generar un detalle mas preciso de estas.

Lo nuevo en PHP 7

Árbol de excepciones en PHP 7
Árbol de excepciones en PHP 7
Con PHP 7, no cambia la jerarquía de las clases Error y Exception sino mas bien estos objetos se hacen mas tratables debido a que ambas implementan la Interface Throwable.
Cuando se emite un error, este se 'transforma' en una excepción y debería ser atrapado en el primer bloque catch() que coincida con el tipo de error, de lo contrario se transforma en un error fatal y se comporta como se conoce, deteniendo el script. Esta nueva excepción sigue siendo un instancia de la clase Error.
Gracias a Throwable ahora podemos capturar tanto errores como excepciones en un bloque try... catch().
/* Lanzando un error y una excepción */
try {
//throw new Error('Este es un error');
//throw new Exception('Esta es una excepción');
} catch(Throwable $e) {
echo $e->getMessage();
}
Tampoco es la panacea jeje. Aun tenemos errores fatales (como exceder el limite de memoria o requerir archivos que no existen) que no son capturados o que son lanzados desde códigos escritos en versiones anteriores de PHP 7.

Interface Throwable

Esta Interface es implementada por las clases Error y Exception.
interface Throwable
{
/* Métodos */
abstract public function getMessage(): string;
abstract public function getCode(): int;
abstract public function getFile(): string;
abstract public function getLine(): string;
abstract public function getTrace(): array();
abstract public function getTraceAsString(): string;
abstract public function getPrevious(): Throwable;
abstract public function __toString():
}
Con PHP 7 tanto la clase Error como la clase Exception implementan esta interface.
Las clases definidas por nosotros no pueden implementar directamente esta interface. Deben extender de las clases Error y Exception.

Propagación de errores

Todos los objetos throwables estarán en la pila de ejecución hasta que ocurra alguna de las siguientes acciones:
  • Encuentre un bloque catch() que soporte el error
  • Exista un manejador de excepciones establecido con set_exception_handler()
  • En ultimo caso, la excepción se convertirá en un error fatal
Asi podemos crear una interface personalizada que implemente Throwable.
/* Implementando una Interface para para extender Throwable */
Interface MiThrowable extends Throwable {
public function metodoPersonalizado();
}
Luego podemos crear una clase para los errores que extienda de Error y que implemente nuestra interface.
/* Implementando una clase personal para manejar errores */
class MiError extends Error implements MiThrowable {
public function metodoPersonalizado() {
// implementamos el código de error personalizado
return "Este es el método personalizado de Error.<br>";
}
}
try {
throw new MiError('Un error personalizado');
} catch(MiError $e) {
echo $e->metodoPersonalizado();
}
O bien, crear una una clase para las excepciones.
/* Implementando una clase personal para manejar excepciones */
class MiExcepcion extends Exception implements MiThrowable {
public function metodoPersonalizado() {
// implementamos el código de excepción personalizado
return "Este es el método personalizado de Exception.<br>";
}
}
try {
throw new MiExcepcion('Una excepción personalizada');
} catch(MiExcepcion $e) {
echo $e->metodoPersonalizado();
}
Tanto las clases MiError como MiExcepcion en los ejemplos anteriores extienden de Error y Exception respectivamente e implementan una interface personalizada MiThrowable que implementa Throwable. Estas clases nos permiten generar errores o excepciones especificas a una condición determinada lo que sera mas útil al momento de depurar la aplicación.
Así podríamos tener implementado algo como:
try { 
//throw new MiError('Un error personalizado');
//throw new MiExcepcion('Una excepción personalizada');
} catch(Throwable $e) {
/* Se atrapa el error pero el script continua */
echo $e->metodoPersonalizado();
echo '<pre><b>Clase</b>: '; print_r(get_class($e)); echo '</pre>';
echo '<pre><b>Linea</b>: '; print_r($e->getLine()); echo '</pre>';
echo '<pre><b>File</b>: '; print_r($e->getFile()); echo '</pre>';
echo '<pre><b>Error</b>: '; print_r($e->getMessage()); echo '</pre>';
exit;
}
Debemos descomentar la linea que lanza el error de tipo MiError o el de tipo MiExcepcion para que podamos ver como funciona. Los errores tipo MiError y MiExcepcion pueden capturarse por ser hijas de la interface Throwable.

Ultimas consideraciones

Ahora y haciendo un resumen, deberíamos preguntarnos ¿Cuando usar una clase que extienda de Error? o ¿Cuando usar una clase que extienda de Exception?.
Los errores provienen en general de fallos en la codificación que necesitan ser atendidos por el programador para continuar con el desarrollo. Pueden ser causados por clases internas de PHP o por la falta de un argumento en una función dada. En general, los objetos de error solo deben capturarse para el registro, realizar cualquier limpieza necesaria y mostrar un mensaje de error al usuario como ultimo caso.
Las excepciones por el contrario, son aquellas de las que debemos tener mayor control en tiempo de ejecución asegurando la continuidad del programa. No dependen del programador pero este debe prever las condiciones de fallo por ejemplo en un formulario.

En el siguiente articulo veremos algunos ejemplos con la clase Error y asi terminar la serie con la clase Exception.

El código fuente de este articulo lo puedes descargar desde acá.

Saludos y nos leemos en el próximo articulo.

Etiquetas php errores

Ultima actualización Jueves 07 de Junio, 2018




Agregar Comentario