Per mostrare gli errori PHP, metti queste righe in cima allo script: ini_set('display_errors', '1'); e error_reporting(E_ALL);. La prima fa stampare a PHP i messaggi di errore, la seconda gli fa segnalare ogni tipo di errore, compresi warning e deprecazioni.
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
Con queste righe, un errore come leggere una variabile mai impostata stampa un messaggio con file e numero di riga invece di fallire in silenzio:
Warning: Undefined variable $total in /home/index.php on line 7
error_reporting() chiamata senza argomenti restituisce l'impostazione corrente come numero. Premi Run per impostare un livello e ritradurlo in nomi:
Ogni tipo di errore è un bit, quindi E_ALL & ~E_DEPRECATED significa "tutto tranne le deprecazioni". Cambia la prima riga in error_reporting(E_ERROR | E_WARNING); ed eseguilo di nuovo.
Mostrare gli errori in php.ini
Un'impostazione nello script vale solo dopo che lo script ha iniziato a girare. Per mostrare gli errori in ogni script, errori di sintassi compresi, modifica php.ini (lo trovi con php --ini):
; Development
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
Riavvia Apache o PHP-FPM dopo la modifica. Il server integrato php -S e la riga di comando leggono il file a ogni avvio. Su un hosting condiviso senza accesso a php.ini, Apache con mod_php accetta anche righe in .htaccess:
php_flag display_errors on
php_value error_reporting -1
-1 imposta tutti i bit, che equivale a E_ALL.
I livelli di errore
| Costante | Cosa lo provoca | Ferma lo script |
|---|---|---|
E_ERROR | Errore fatale a runtime, come l'esaurimento della memoria | sì |
E_PARSE | Errore di sintassi nel file | sì |
E_WARNING | Variabile o chiave di array non definita, file mancante in include | no |
E_NOTICE | Problemi minori (in PHP 8 ne restano pochi) | no |
E_DEPRECATED | Codice che una futura versione di PHP rifiuterà | no |
E_USER_* | Errori che sollevi tu con trigger_error() | solo E_USER_ERROR |
E_ALL | Tutti i livelli, compresi errori del core e di compilazione non elencati qui |
PHP 8.0 ha trasformato molti vecchi warning in eccezioni: dividere per zero con / e passare il tipo sbagliato a una funzione integrata ora lanciano una sottoclasse di Error, come succede da PHP 7 quando chiami una funzione non definita. Puoi catturarli tutti e tre:
Le eccezioni sono trattate in try e catch. Warning, notice e deprecazioni passano ancora dal sistema di segnalazione degli errori descritto qui.
Registrare gli errori nel log invece di mostrarli
Su un sito in produzione i visitatori non devono mai vedere messaggi di errore: rivelano percorsi, SQL e codice. Scrivili invece in un file di log:
; Production
display_errors = Off
log_errors = On
error_log = /var/log/php/app-errors.log
error_reporting = E_ALL
Mantieni error_reporting = E_ALL in produzione. Abbassarlo non fa sparire gli errori, impedisce solo che tu ne venga a sapere. Anche i tuoi messaggi possono finire nello stesso log con error_log():
<?php
error_log("Payment failed for order 1042");
Poi tieni d'occhio il file mentre fai i test: tail -f /var/log/php/app-errors.log.
Trasformare i warning in eccezioni con set_error_handler
set_error_handler sostituisce la gestione predefinita di warning, notice e deprecazioni con una tua funzione. Uno schema comune li converte tutti in ErrorException, così una chiave di array dimenticata ferma il codice come qualsiasi altra eccezione e può essere catturata:
Il gestore riceve il livello dell'errore come primo argomento, quindi può trattare i livelli in modo diverso. Questo registra solo le deprecazioni e trasforma tutto il resto in un'eccezione:
Gli errori fatali e gli errori di sintassi non arrivano mai al gestore, perché dopo di essi lo script non può continuare. Per registrarli, registra una funzione di shutdown che legge error_get_last().
Leggere l'ultimo errore con error_get_last
Alcune funzioni restituiscono false e riportano il motivo solo come warning, per esempio file_get_contents su un file mancante. error_get_last() restituisce quel warning come array, utile quando vuoi mostrare un tuo messaggio:
L'operatore @ davanti alla chiamata sopprime il messaggio per quella sola espressione. Usalo con parsimonia e solo quando controlli il risultato subito dopo, come qui; una @ da sola nasconde soltanto i bug.
Errore comune: gli errori sono attivi, ma la pagina è ancora bianca
Se hai aggiunto ini_set('display_errors', '1') e vedi ancora una pagina bianca, probabilmente l'errore è di sintassi. PHP analizza tutto il file prima di eseguire la prima riga, quindi un ; o una } mancanti fermano tutto prima che ini_set venga eseguita. Controlla il file dal terminale, che stampa sempre il messaggio:
php -l index.php
Errors parsing index.php
PHP Parse error: syntax error, unexpected token "," in index.php on line 2
Il numero di riga indica dove PHP si è arreso, che spesso è la riga dopo l'errore vero. Correggilo, esegui di nuovo php -l finché non dice No syntax errors detected, poi ricarica la pagina.
Domande frequenti
Come mostro tutti gli errori in PHP?
Aggiungi ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); proprio in cima allo script, oppure imposta display_errors = On ed error_reporting = E_ALL in php.ini e riavvia il web server o PHP-FPM.
Perché la mia pagina PHP mostra una schermata bianca?
Un errore fatale ha fermato lo script mentre display_errors è disattivato, quindi non è stato stampato nulla. Attiva gli errori (oppure leggi il log degli errori, per esempio con tail -f sul file indicato da error_log) per vedere il messaggio e il numero di riga.
Perché ini_set('display_errors', 1) non mostra il mio errore di sintassi?
Un errore di sintassi ferma PHP prima che venga eseguita qualsiasi riga del file, quindi la chiamata a ini_set non avviene mai. Imposta display_errors in php.ini, oppure metti ini_set in un piccolo file che poi fa include di quello rotto.
display_errors deve essere attivo in produzione?
No. I messaggi di errore rivelano ai visitatori percorsi dei file e dettagli del codice. In produzione usa display_errors = Off, log_errors = On e un percorso per error_log, e mantieni error_reporting = E_ALL così i problemi vengono comunque registrati.
Cosa fa error_reporting(0)?
Disattiva la segnalazione di ogni tipo di errore per il resto dello script, quindi warning e persino errori fatali non producono alcun messaggio. Nasconde i problemi invece di risolverli; meglio registrare gli errori nel log che silenziarli.