Para mostrar los errores de PHP, pon estas líneas al principio de tu script: ini_set('display_errors', '1'); y error_reporting(E_ALL);. La primera hace que PHP imprima los mensajes de error; la segunda, que informe de todos los tipos de error, incluidos los warnings y los avisos de obsolescencia.
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
Con eso, un fallo como leer una variable que nunca se definió imprime un mensaje con el archivo y el número de línea en lugar de fallar en silencio:
Warning: Undefined variable $total in /home/index.php on line 7
error_reporting() llamado sin argumentos devuelve la configuración actual como número. Pulsa Ejecutar para fijar un nivel y traducirlo de vuelta a nombres:
Cada tipo de error es un bit, así que E_ALL & ~E_DEPRECATED significa "todo menos los avisos de obsolescencia". Cambia la primera línea por error_reporting(E_ERROR | E_WARNING); y vuelve a ejecutarlo.
Mostrar errores en php.ini
Una configuración en el script solo se aplica una vez que el script empieza a ejecutarse. Para mostrar los errores de todos los scripts, incluidos los errores de sintaxis, cambia php.ini (encuéntralo con php --ini):
; Development
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
Reinicia Apache o PHP-FPM después de editarlo. El servidor integrado php -S y la línea de comandos leen el archivo cada vez que arrancan. En un hosting compartido sin acceso a php.ini, Apache con mod_php también acepta líneas en .htaccess:
php_flag display_errors on
php_value error_reporting -1
-1 activa todos los bits, lo que equivale a E_ALL.
Los niveles de error
| Constante | Qué lo provoca | Detiene el script |
|---|---|---|
E_ERROR | Error fatal en tiempo de ejecución, como quedarse sin memoria | sí |
E_PARSE | Error de sintaxis en el archivo | sí |
E_WARNING | Variable o clave de array no definida, archivo que falta en include | no |
E_NOTICE | Problemas menores (quedan pocos en PHP 8) | no |
E_DEPRECATED | Código que una versión futura de PHP rechazará | no |
E_USER_* | Errores que lanzas tú con trigger_error() | solo E_USER_ERROR |
E_ALL | Todos los niveles, incluidos los errores de núcleo y de compilación que no aparecen aquí |
PHP 8.0 convirtió muchos warnings antiguos en excepciones: dividir por cero con / y pasar un tipo incorrecto a una función nativa ahora lanzan una subclase de Error, igual que llamar a una función no definida desde PHP 7. Puedes capturar los tres:
Las excepciones se explican en try y catch. Los warnings, los notices y los avisos de obsolescencia siguen pasando por el sistema de reporte de errores que se describe aquí.
Registrar los errores en lugar de mostrarlos
En un sitio en producción, los visitantes nunca deberían ver mensajes de error: revelan rutas, SQL y código. Escríbelos en un archivo de log:
; Production
display_errors = Off
log_errors = On
error_log = /var/log/php/app-errors.log
error_reporting = E_ALL
Mantén error_reporting = E_ALL en producción. Bajarlo no hace desaparecer los errores, solo hace que dejes de enterarte de ellos. Tus propios mensajes pueden ir al mismo log con error_log():
<?php
error_log("Payment failed for order 1042");
Después vigila el archivo mientras pruebas: tail -f /var/log/php/app-errors.log.
Convertir warnings en excepciones con set_error_handler
set_error_handler sustituye el manejo por defecto de PHP para warnings, notices y avisos de obsolescencia por tu propia función. Un patrón habitual convierte cada uno en una ErrorException, de modo que una clave de array olvidada detiene el código como cualquier otra excepción y se puede capturar:
El manejador recibe el nivel del error como primer argumento, así que puede tratar cada nivel de forma distinta. Este solo registra los avisos de obsolescencia y convierte todo lo demás en una excepción:
Los errores fatales y los de sintaxis nunca llegan al manejador, porque el script no puede continuar después de ellos. Para registrarlos, registra una función de cierre que lea error_get_last().
Leer el último error con error_get_last
Algunas funciones devuelven false e informan del motivo solo como warning, por ejemplo file_get_contents con un archivo que no existe. error_get_last() devuelve ese warning como array, algo útil cuando quieres mostrar tu propio mensaje:
El operador @ delante de la llamada suprime el mensaje para esa única expresión. Úsalo con moderación y solo cuando compruebes el resultado justo después, como aquí; un @ por sí solo solo esconde errores.
Error frecuente: los errores están activados, pero la página sigue en blanco
Si añadiste ini_set('display_errors', '1') y sigues viendo una página en blanco, probablemente sea un error de sintaxis. PHP analiza el archivo entero antes de ejecutar la primera línea, así que un ; o una } que falte lo detiene todo antes de que se ejecute ini_set. Comprueba el archivo desde la terminal, que siempre imprime el mensaje:
php -l index.php
Errors parsing index.php
PHP Parse error: syntax error, unexpected token "," in index.php on line 2
El número de línea señala dónde se rindió PHP, que a menudo es la línea siguiente al error real. Corrígelo, ejecuta php -l de nuevo hasta que diga No syntax errors detected y recarga la página.
Preguntas frecuentes
¿Cómo muestro todos los errores en PHP?
Añade ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); al principio del script, o configura display_errors = On y error_reporting = E_ALL en php.ini y reinicia el servidor web o PHP-FPM.
¿Por qué mi página PHP muestra una pantalla en blanco?
Un error fatal detuvo el script mientras display_errors estaba desactivado, así que no se imprimió nada. Activa los errores (o lee el log de errores, por ejemplo con tail -f sobre el archivo al que apunta error_log) para ver el mensaje y el número de línea.
¿Por qué ini_set('display_errors', 1) no muestra mi error de sintaxis?
Un error de sintaxis detiene PHP antes de que se ejecute cualquier línea del archivo, así que la llamada a ini_set nunca ocurre. Configura display_errors en php.ini, o pon el ini_set en un archivo pequeño que luego haga include del archivo roto.
¿Debe estar activado display_errors en producción?
No. Los mensajes de error revelan rutas de archivos y detalles del código a los visitantes. En producción usa display_errors = Off, log_errors = On y una ruta en error_log, y mantén error_reporting = E_ALL para que los problemas sigan quedando registrados.
¿Qué hace error_reporting(0)?
Desactiva el reporte de todos los tipos de error durante el resto del script, así que los warnings e incluso los errores fatales no producen ningún mensaje. Oculta los problemas en lugar de corregirlos; es mejor registrar los errores en un log que silenciarlos.