En numerosas ocasiones necesitamos depurar errores de scripts PHP que corren en un servidor con la visualización de errores deshabilitada, lo que nos impide ver qué está fallando en pantalla. Esto, recomendable en producción, se vuelve un problema cuando el error no se repite en el entorno de desarrollo. Aquí tienes cómo mostrar los errores solo donde los necesitas, cómo registrarlos sin exponerlos y cómo llevar la depuración un paso más allá.
01 El problema: errores ocultos en producción
Por defecto, muchos servidores y paneles traen display_errors = Off y error_reporting limitado. Es lo correcto para producción: un error fatal no debería mostrar el path, el SQL ni la traza al visitante (fuga de información). Pero cuando el fallo solo aparece en el servidor, necesitamos activar la visualización temporalmente, idealmente en una sola página y no en todo el sitio.
En producción nunca muestres el error completo en pantalla; regístralo en un log. Mostrar la traza al usuario final es una puerta abierta a filtrar rutas, credenciales o consultas. Usa la técnica de esta página solo para depurar, y desactívala al terminar.
02 Mostrar errores solo en la página a depurar
Para activar la visualización de errores únicamente en un script, usamos ini_set() (cambia un parámetro del servidor solo para la ejecución en curso, no se mantiene para las siguientes peticiones) y error_reporting() para elegir el nivel. Dos líneas al comienzo de la página (después de <?php) bastan:
<?php
error_reporting(E_ALL & ~E_NOTICE); // todos los errores salvo los avisos poco relevantes
ini_set("display_errors", 1); // mostrar errores en pantalla
?>
Si además quieres forzar el reporte aunque el código lo cambie después, puedes añadir ini_set('error_reporting', E_ALL). Para solo consultar un valor actual (sin cambiarlo): ini_get("display_errors") o ini_get("error_reporting").
03 Niveles de error en PHP
El parámetro de error_reporting() es un suma binaria de los niveles que quieres ver. Estos son los más relevantes (los combinas con |):
| Valor | Etiqueta | Qué significa |
|---|---|---|
| 1 | E_ERROR | Error fatal en tiempo de ejecución; no se puede recuperar, la ejecución se interrumpe. |
| 2 | E_WARNING | Advertencia (no fatal); la ejecución continúa. |
| 4 | E_PARSE | Error de análisis en tiempo de compilación. |
| 8 | E_NOTICE | Aviso (posible error, pero puede ser normal en la ejecución). |
| 256 | E_USER_ERROR | Error generado por el código con trigger_error(). |
| 2048 | E_STRICT | Desaconseja cambios para compatibilidad con futuras versiones. |
| 4096 | E_RECOVERABLE_ERROR | Error capturable; si nadie lo captura, la app se aborta. |
| 8192 | E_DEPRECATED | Aviso de código que no funcionará en futuras versiones. |
| 30719 | E_ALL | Todos los errores y advertencias soportados (salvo E_STRICT). |
Combinaciones típicas: error_reporting(E_ALL) (todo, para desarrollo), error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED) (todo menos avisos ruidosos).
04 Registrar en log en lugar de mostrar en pantalla
Para producción, lo correcto es escribir los errores en un fichero y no mostrarlos:
ini_set("display_errors", 0); // nunca en pantalla en producción
ini_set("log_errors", 1); // activa el registro
ini_set("error_log", "/var/log/php_errors.log"); // dónde escribirlo
También puedes escribir un mensaje puntual con la función error_log(), muy útil para «marcar» un punto concreto del código:
error_log("Llegué aquí, valor de \$x = " . var_export($x, true));
Para verlo en directo mientras desarrollas: tail -f /var/log/php_errors.log.
05 Gestor de errores propio y excepciones
Con set_error_handler() puedes capturar los errores (incluidos avisos) y decidir qué hacer con ellos. Y para errores que lanzas desde tu código, captúralos con try/catch, capturando \Throwable (abarca Error y Exception):
set_error_handler(function ($severity, $message, $file, $line) {
error_log("[$severity] $message en $file:$line");
// no interrumpir la ejecución para avisos no fatales
if ($severity === E_USER_ERROR) { return false; }
return true;
});
try {
// código que puede fallar
} catch (\Throwable $e) {
error_log($e->getMessage());
echo "Ha ocurrido un problema; revisa el log.";
}
06 Otros ajustes útiles para depurar
ini_set("memory_limit", "256M"); // límite de memoria del script
ini_set("max_execution_time", "60"); // tiempo máximo de ejecución en segundos
ini_set("display_errors", 1);
ini_set("html_errors", 1); // traza con formato HTML (más legible)
var_dump($variable); // volcar el valor de una variable
Si el hosting usa Apache y ini_set() no surte efecto (por ejemplo en .htaccess), puedes declarar valores por directorio (según versión de PHP):
php_value display_errors 1
php_value error_reporting 32767
07 Depurar desde la línea de comandos
Cuando puedes ejecutar por terminal, la depuración es mucho más directa:
php -l script.php # comprueba la sintaxis (lint) sin ejecutar
php -d display_errors=1 script.php # ejecuta mostrando errores
php -d error_reporting=32767 script.php
Si además tienes Xdebug, puedes forzar el registro con xdebug.log y activar la pila de llamadas; y en muchos entornos, con xdebug.mode=debug y un cliente, haces step debugging real.
08 Conclusión
Mostrar errores ocultos en PHP es tan sencillo como dos líneas (error_reporting(E_ALL) + ini_set("display_errors",1)) y tan peligroso como dejarlas en producción. La buena práctica es: en desarrollo muestra todo, en producción registra en log, y usa set_error_handler()/`try-catch` para gestionar lo que te importa y no mostrar trazas al usuario.