Menu

Wyświetlanie błędów PHP: display_errors i E_ALL

Aby pokazać wszystkie błędy PHP, wstaw ini_set('display_errors', '1'); i error_reporting(E_ALL); na początku skryptu albo ustaw display_errors = On i error_reporting = E_ALL w php.ini. Na produkcji zapisuj błędy do logu zamiast je wyświetlać.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Aby pokazać błędy PHP, wstaw na początku skryptu te linie: ini_set('display_errors', '1'); i error_reporting(E_ALL);. Pierwsza sprawia, że PHP wypisuje komunikaty błędów, druga, że zgłasza każdy rodzaj błędu, łącznie z ostrzeżeniami i informacjami o przestarzałym kodzie.

<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

Z tymi ustawieniami błąd taki jak odczyt zmiennej, której nigdy nie ustawiono, wypisuje komunikat z plikiem i numerem linii, zamiast cicho zawieść:

Warning: Undefined variable $total in /home/index.php on line 7

error_reporting() wywołane bez argumentu zwraca bieżące ustawienie jako liczbę. Kliknij Run, aby ustawić poziom i odczytać go z powrotem jako nazwy:

Każdy typ błędu to jeden bit, więc E_ALL & ~E_DEPRECATED oznacza „wszystko oprócz informacji o przestarzałym kodzie”. Zmień pierwszą linię na error_reporting(E_ERROR | E_WARNING); i uruchom ponownie.

Wyświetlanie błędów w php.ini

Ustawienie w skrypcie działa dopiero, gdy skrypt zacznie się wykonywać. Aby pokazywać błędy dla każdego skryptu, łącznie z błędami parsowania, zmień php.ini (znajdziesz go przez php --ini):

; Development
display_errors = On
display_startup_errors = On
error_reporting = E_ALL

Po edycji zrestartuj Apache albo PHP-FPM. Wbudowany serwer php -S i wiersz poleceń czytają plik przy każdym starcie. Na hostingu współdzielonym bez dostępu do php.ini Apache z mod_php przyjmuje też linie w .htaccess:

php_flag display_errors on
php_value error_reporting -1

-1 ustawia każdy bit, czyli to samo co E_ALL.

Poziomy błędów

StałaCo ją wywołujeZatrzymuje skrypt
E_ERRORKrytyczny błąd w czasie działania, na przykład brak pamięcitak
E_PARSEBłąd składni w plikutak
E_WARNINGNiezdefiniowana zmienna lub klucz tablicy, brak pliku w includenie
E_NOTICEDrobne problemy (w PHP 8 zostało ich niewiele)nie
E_DEPRECATEDKod, który przyszła wersja PHP odrzucinie
E_USER_*Błędy zgłaszane przez Ciebie przez trigger_error()tylko E_USER_ERROR
E_ALLKażdy poziom, łącznie z błędami rdzenia i kompilacji, których tu nie wymieniono

PHP 8.0 zamienił wiele starych ostrzeżeń w wyjątki: dzielenie przez zero operatorem / i przekazanie złego typu do wbudowanej funkcji rzucają teraz podklasę Error, tak samo jak wywołanie niezdefiniowanej funkcji od PHP 7. Wszystkie trzy możesz przechwycić:

Wyjątki są opisane w try i catch. Ostrzeżenia, notice i informacje o przestarzałym kodzie nadal przechodzą przez opisany tu system raportowania błędów.

Logowanie błędów zamiast wyświetlania

Na działającej stronie odwiedzający nigdy nie powinni widzieć komunikatów błędów: ujawniają ścieżki, SQL i kod. Zapisuj je zamiast tego do pliku logu:

; Production
display_errors = Off
log_errors = On
error_log = /var/log/php/app-errors.log
error_reporting = E_ALL

Zostaw error_reporting = E_ALL na produkcji. Obniżenie poziomu nie usuwa błędów, tylko sprawia, że się o nich nie dowiadujesz. Własne komunikaty możesz zapisać do tego samego logu przez error_log():

<?php
error_log("Payment failed for order 1042");

Potem obserwuj plik podczas testów: tail -f /var/log/php/app-errors.log.

Zamiana ostrzeżeń w wyjątki przez set_error_handler

set_error_handler zastępuje domyślną obsługę ostrzeżeń, notice i informacji o przestarzałym kodzie Twoją własną funkcją. Popularny wzorzec zamienia każde z nich w ErrorException, więc zapomniany klucz tablicy zatrzymuje kod jak każdy inny wyjątek i można go przechwycić:

Funkcja obsługi dostaje poziom błędu jako pierwszy argument, więc może traktować poziomy różnie. Ta tylko loguje informacje o przestarzałym kodzie, a całą resztę zamienia w wyjątek:

Błędy krytyczne i błędy parsowania nigdy nie trafiają do funkcji obsługi, bo skrypt nie może po nich kontynuować. Aby je zapisać, zarejestruj funkcję zamykającą, która czyta error_get_last().

Odczyt ostatniego błędu przez error_get_last

Niektóre funkcje zwracają false i podają przyczynę tylko jako ostrzeżenie, na przykład file_get_contents dla nieistniejącego pliku. error_get_last() zwraca to ostrzeżenie jako tablicę, co się przydaje, gdy chcesz pokazać własny komunikat:

Operator @ przed wywołaniem wycisza komunikat dla tego jednego wyrażenia. Używaj go oszczędnie i tylko wtedy, gdy zaraz potem sprawdzasz wynik, jak tutaj; samo @ jedynie ukrywa błędy.

Częsty błąd: błędy są włączone, a strona nadal jest pusta

Jeśli dodałeś ini_set('display_errors', '1') i nadal widzisz białą stronę, to prawdopodobnie błąd parsowania. PHP parsuje cały plik przed wykonaniem pierwszej linii, więc brakujący ; albo } zatrzymuje wszystko, zanim wykona się ini_set. Sprawdź plik z terminala, który zawsze wypisuje komunikat:

php -l index.php
Errors parsing index.php
PHP Parse error:  syntax error, unexpected token "," in index.php on line 2

Numer linii wskazuje miejsce, w którym PHP się poddał, a to często linia po faktycznym błędzie. Popraw go, uruchamiaj php -l, aż wypisze No syntax errors detected, i odśwież stronę.

Najczęściej zadawane pytania

Jak wyświetlić wszystkie błędy w PHP?

Dodaj ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); na samym początku skryptu albo ustaw display_errors = On i error_reporting = E_ALL w php.ini i zrestartuj serwer WWW lub PHP-FPM.

Dlaczego moja strona PHP pokazuje pusty biały ekran?

Błąd krytyczny zatrzymał skrypt przy wyłączonym display_errors, więc nic się nie wypisało. Włącz wyświetlanie błędów (albo przeczytaj log błędów, na przykład przez tail -f na pliku, na który wskazuje error_log), aby zobaczyć komunikat i numer linii.

Dlaczego ini_set('display_errors', 1) nie pokazuje mojego błędu parsowania?

Błąd parsowania zatrzymuje PHP, zanim wykona się jakakolwiek linia pliku, więc wywołanie ini_set nigdy nie następuje. Ustaw display_errors w php.ini albo umieść ini_set w małym pliku, który potem dołącza przez include ten zepsuty.

Czy display_errors powinno być włączone na produkcji?

Nie. Komunikaty błędów ujawniają odwiedzającym ścieżki plików i szczegóły kodu. Na produkcji użyj display_errors = Off, log_errors = On i ścieżki w error_log, a error_reporting = E_ALL zostaw, żeby problemy nadal były zapisywane.

Co robi error_reporting(0)?

Wyłącza raportowanie wszystkich typów błędów do końca skryptu, więc ostrzeżenia, a nawet błędy krytyczne nie dają żadnego komunikatu. To ukrywa problemy, zamiast je naprawiać; lepiej logować błędy niż je wyciszać.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ