En este HowTo veremos como detectar y tratar los errores que se produzcan en nuestra aplicaciones PHP en «tiempo de ejecución«.
Actualmente disponemos de muchas herramientas para poder controlar los errores que se produzcan en nuestros programas. Trabajar con un IDE es la forma más sencilla de detectarlos por lo que no hacer uso de ellos es complicarnos la vida.
Estos programas nos facilitan la escritura del código, nos ofrecen sugerencias y recomendaciones de uso de funciones según vamos tecleando nuestro código. En caso de no existir una función, errores de escritura, etc … este nos avisará indicando la posición exacta del error e incluso alternativas para poder solucionarlo.
En PHP existen diversas formas de tratar errores (excepciones, xdebug, etc …) pero para empezar nos centraremos en la detección de errores en tiempo de ejecución. Para ello profundzaremos en el uso de la función init_set
de PHP y todas sus directivas mas relevantes relacionadas con el control de errores.
Una vez nos hagamos con la teoría escribiremos una clase para poder aplicar estas directivas, cómo registrar errores personalizados y cómo incorporarlas a nuestros scripts.
init_set()
init_set
es una función de PHP que nos va a permitir definir directivas de configuración específicas (y que en este caso utilizaremos para controlar errores).
1 |
in init_set( $variable, $valor) |
Entre las directivas de control de errores que vamos a poder controlar, podemos destacar las siguientes:
- error_reporting (defecto NULL)
- display_errors (defecto 1)
- display_startup_errors (defecto 0)
- error_append_string (defecto NULL)
- error_log (defecto NULL)
- error_prepend_string (defecto NULL)
- error_reporting (defecto NULL)
- html_errors (defecto 1)
- ignore_repeated_errors (defecto 0)
- ignore_repeated_source (defecto 0)
- log_errors (defecto 0)
- log_errors_max_len (defecto 1024 bytes)
error_reporting
error_reporting nos permite establecer mediante el uso de constantes el nivel de notificación de los errores. Para versiones PHP5.3> el valor predeterminado es E_ALL & ~E_NOTICE
Aunque se puede declarar de 2 formas diferentes, nos centraremos en la segunda:
1 2 |
error_reporting(E_ALL); ini_set("error_reporting", E_ALL); |
Las constantes más utilizadas para utilizar junto a error_reporting son las siguientes:
- E_ALL notifica caulquier tipo de error que se produzca.
- E_NOTICE permite controlar errores producidos en la escritura de código PHP, variables no inicializadas, etc …
- E_WARNING muestra advertencias pero estas no impiden que la ejecución del script continue.
- E_PARSE muestra errores de análisis de código como pueden ser llaves no cerradas, comillas de cierre no incluidas, etc ..
- E_ERROR Son errores fatales en tiempo de ejecución, por lo que la ejecución del script se interrumpe.
Si necesitas consultar más información sobre las constantes de error, haz clic aquí.
display_errors
Esta directiva visualiza todos los errores que se produzcan directamente en pantalla. Y aunque por defecto está activada es recomendable desactivarla en entornos de producción para ocultar estos errores a los usuarios que naveguen por la página.
1 |
ini_set("display_errors", 0); |
log_errors
log_errors nos permite especificar que los errores deben registrarse en un fichero de error, que por defecto estará ubicado y gestionado por el propio servidor web (nginx, apache, etc …).
En un sitio web en producción deberíamos activar esta directiva de configuración para así poder registrar los errores que se produzcan y poder consultarlos cuando sea necesario.
1 |
ini_set("log_errors", 1); |
log_errors_max_len
log_errors_max_len permite establecer una longitud máxima del error (en bytes). Su valor predeterminado es 1024 y establecer su valor a 0 indica que no queremos ninguna limitación de espacio.
1 |
ini_set("log_errors_max_len", 0); |
ignore_repeated_errors
ignore_repeated_errors evita que se muestren errores redundantes por lo que así evitamos que nuestro fichero de errores engorde excesivamente. Por defecto esta desactivada.
ini_set(«ignore_repeated_errors», 0);
1 |
ini_set("ignore_repeated_errors", 0); |
ignore_repeated_source
Funciona muy parecido a ignore_repeated_errors pero además ignora errores que se repitan en diferentes ficheros.
1 |
ini_set("ignore_repeated_source", 0); |
html_errors
Habilitar html_errors muestra errores clicables con información adicional sobre el tipo de error que lo ha causado (no es muy preciso).
1 |
ini_set("html_errors", 0); |
error_prepend_string y error_append_string
Estas directivas están desactivadas por defecto y es importante saber que sólo tienen utilidad con display_errors activado. Nos permiten incluir código antes y después del error por lo que podríamos incluir información adicional o incluso decorar el error con etiquetas HTML y CSS.
1 2 |
ini_set("'error_prepend_string' => '<div style="color:#ff0000">'); ini_set("'error_append_string' => '</div>'); |
error_log
error_log es una directiva importante ya que nos permite especificar errores personalizados y dónde deben registrarse en caso de producirse. En caso de no indicar un fichero donde almacenar el error, se utilizará el que tenga establecido por defecto el servidor web en su configuración.
1 |
error_log ( 'mensaje de error, advertencia, etc ...', tipo_de_registro, destino, headers ) |
Los tipos de registro tienen diferentes niveles, entre los que podemos destacar los siguientes:
- 0 (por defecto) corresponde a un mensaje que queremos guardar.
- 1 cuando queremos que el mensaje sea enviado por correo electrónico (en este caso necesitamos completar el último parámetro de headers)
- 3 nos permite indicar el fichero donde registrar el tipo de error.
Veamos como registrar un error sencillo (nivel 0) en el fichero de log que se tenga definido por defecto.
1 2 |
error_log("Ha ocurrido un error con el pago del pedido X"); error_log("El pedido x tiene portes 0"); |
Ahora veamos como personalizar el error (nivel 3) guardando su mensaje a un fichero elegido a nuestra elección.
1 |
error_log("Error Grave, no se ha podido conectar con la BD ...", 3, "logs/critical.log"); |
Ahora veamos cómo poder reportar un error de (nivel 1) vía correo electrónico, siempre que necesitemos estar informado cuando este se produzca.
1 2 3 4 5 |
$headers = 'Content-Type: text/html; charset=utf-8' . "\r\n"; $headers .= 'From: jose@aregrafico.net' . "\r\n"; $headers .= 'Reply-To: jose@artegrafico.net' . "\r\n"; $headers .= 'X-Mailer: PHP/' . phpversion(); error_log("Error Grave. No se ha podido conectar con la BD", 1, 'jose@artegrafico.net', $headers); |
Creando una Clase para control de errores
Una vez tenemos algo más clara la teoría vamos a crear una clase para controlar errores en tiempo de ejecución. Aunque esta clase también controla excepciones, estos los trataremos más adelante. La clase se puede descargar y consultar en GitHub,
Su forma de uso es bastante sencilla, a continuación podéis consultar diferentes formas de uso:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
if (class_exists ('debugguer')) { $debugguer = new debugguer(true); // errores por defecto de nivel 0 $debugguer->log("Se ha producido un error1 ..."); // errores personalizados de nivel 3 $debugguer->log("Se ha producido un error2 ...", "error"); $debugguer->log("Pedido inferior a 5€ ...", "info"); $debugguer->log("Se ha producido un error crítico ...", "critical"); $debugguer->log("No se pudo conectar con la Base de Datos ...", "fatal"); // errores de nivel 1 debugguer->log_to_mail("La conexión hacia la DB ha fallado", "jose@artegrafico.net"); } |