Um PHP-Fehler anzuzeigen, schreib diese Zeilen an den Anfang deines Skripts: ini_set('display_errors', '1'); und error_reporting(E_ALL);. Die erste sorgt dafür, dass PHP Fehlermeldungen ausgibt, die zweite, dass es jede Art von Fehler meldet, auch Warnungen und Deprecations.
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
Damit gibt ein Fehler, etwa das Lesen einer nie gesetzten Variable, eine Meldung mit Datei und Zeilennummer aus, statt still zu scheitern:
Warning: Undefined variable $total in /home/index.php on line 7
error_reporting() ohne Argument liefert die aktuelle Einstellung als Zahl. Klicke auf Run, um eine Stufe zu setzen und sie wieder in Namen zu übersetzen:
Jeder Fehlertyp ist ein Bit, deshalb bedeutet E_ALL & ~E_DEPRECATED „alles außer Deprecations“. Ändere die erste Zeile in error_reporting(E_ERROR | E_WARNING); und führe den Code erneut aus.
Fehler in der php.ini anzeigen
Eine Einstellung im Skript gilt erst, sobald das Skript läuft. Um Fehler für jedes Skript anzuzeigen, auch Parse-Fehler, änderst du die php.ini (finde sie mit php --ini):
; Development
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
Starte Apache oder PHP-FPM nach dem Bearbeiten neu. Der eingebaute Server php -S und die Kommandozeile lesen die Datei bei jedem Start. Auf Shared Hosting ohne Zugriff auf die php.ini akzeptiert Apache mit mod_php auch Zeilen in der .htaccess:
php_flag display_errors on
php_value error_reporting -1
-1 setzt jedes Bit und ist damit dasselbe wie E_ALL.
Die Fehlerstufen
| Konstante | Was sie auslöst | Stoppt das Skript |
|---|---|---|
E_ERROR | Fataler Laufzeitfehler, etwa wenn der Speicher ausgeht | ja |
E_PARSE | Syntaxfehler in der Datei | ja |
E_WARNING | Undefinierte Variable oder undefinierter Array-Schlüssel, fehlende Datei bei include | nein |
E_NOTICE | Kleinere Probleme (in PHP 8 gibt es nur noch wenige) | nein |
E_DEPRECATED | Code, den eine zukünftige PHP-Version ablehnen wird | nein |
E_USER_* | Fehler, die du mit trigger_error() auslöst | nur E_USER_ERROR |
E_ALL | Jede Stufe, auch Core- und Compile-Fehler, die hier nicht aufgeführt sind |
PHP 8.0 hat viele alte Warnungen in Exceptions umgewandelt: Division durch null mit / und die Übergabe eines falschen Typs an eine eingebaute Funktion werfen jetzt eine Unterklasse von Error, so wie es der Aufruf einer undefinierten Funktion seit PHP 7 tut. Alle drei kannst du abfangen:
Exceptions werden unter try und catch behandelt. Warnungen, Notices und Deprecations laufen weiterhin über das hier beschriebene Fehlersystem.
Fehler protokollieren statt anzeigen
Auf einer Live-Website sollten Besucher nie Fehlermeldungen sehen: Sie verraten Pfade, SQL und Code. Schreib sie stattdessen in eine Logdatei:
; Production
display_errors = Off
log_errors = On
error_log = /var/log/php/app-errors.log
error_reporting = E_ALL
Behalte error_reporting = E_ALL auch in Produktion. Wenn du es herunterdrehst, verschwinden die Fehler nicht, du erfährst nur nichts mehr davon. Eigene Meldungen können mit error_log() ins selbe Log gehen:
<?php
error_log("Payment failed for order 1042");
Beobachte die Datei dann beim Testen: tail -f /var/log/php/app-errors.log.
Warnungen mit set_error_handler in Exceptions umwandeln
set_error_handler ersetzt die Standardbehandlung von Warnungen, Notices und Deprecations durch deine eigene Funktion. Ein gängiges Muster wandelt jede davon in eine ErrorException um, sodass ein vergessener Array-Schlüssel den Code wie jede andere Exception stoppt und abgefangen werden kann:
Der Handler bekommt die Fehlerstufe als erstes Argument und kann Stufen deshalb unterschiedlich behandeln. Dieser hier protokolliert nur Deprecations und macht aus allem anderen eine Exception:
Fatale Fehler und Parse-Fehler erreichen den Handler nie, weil das Skript danach nicht weiterlaufen kann. Um sie aufzuzeichnen, registrierst du eine Shutdown-Funktion, die error_get_last() ausliest.
Den letzten Fehler mit error_get_last lesen
Manche Funktionen geben false zurück und melden den Grund nur als Warnung, zum Beispiel file_get_contents bei einer fehlenden Datei. error_get_last() liefert diese Warnung als Array. Das ist praktisch, wenn du eine eigene Meldung anzeigen willst:
Der Operator @ vor dem Aufruf unterdrückt die Meldung für genau diesen einen Ausdruck. Setze ihn sparsam ein und nur, wenn du das Ergebnis direkt danach prüfst, wie hier; ein @ allein versteckt nur Bugs.
Typischer Fehler: Fehlerausgabe ist an, aber die Seite bleibt leer
Wenn du ini_set('display_errors', '1') eingefügt hast und trotzdem eine weiße Seite siehst, ist der Fehler wahrscheinlich ein Parse-Fehler. PHP parst die ganze Datei, bevor die erste Zeile läuft, also stoppt ein fehlendes ; oder } alles, bevor ini_set ausgeführt wird. Prüfe die Datei im Terminal, das die Meldung immer ausgibt:
php -l index.php
Errors parsing index.php
PHP Parse error: syntax error, unexpected token "," in index.php on line 2
Die Zeilennummer zeigt, wo PHP aufgegeben hat, und das ist oft die Zeile nach dem eigentlichen Fehler. Behebe ihn, führe php -l erneut aus, bis No syntax errors detected erscheint, und lade dann die Seite neu.
Häufig gestellte Fragen
Wie zeige ich alle Fehler in PHP an?
Schreib ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); ganz an den Anfang des Skripts oder setze display_errors = On und error_reporting = E_ALL in der php.ini und starte den Webserver oder PHP-FPM neu.
Warum zeigt meine PHP-Seite nur eine weiße Seite?
Ein fataler Fehler hat das Skript beendet, während display_errors aus ist, also wurde nichts ausgegeben. Schalte die Fehlerausgabe ein (oder lies das Fehlerlog, zum Beispiel mit tail -f auf die Datei, auf die error_log zeigt), um die Meldung und die Zeilennummer zu sehen.
Warum zeigt ini_set('display_errors', 1) meinen Parse-Fehler nicht an?
Ein Parse-Fehler stoppt PHP, bevor auch nur eine Zeile der Datei läuft, also wird der Aufruf von ini_set nie ausgeführt. Setze display_errors in der php.ini oder schreib das ini_set in eine kleine Datei, die dann die fehlerhafte per include einbindet.
Sollte display_errors in Produktion eingeschaltet sein?
Nein. Fehlermeldungen verraten Besuchern Dateipfade und Details zum Code. In Produktion verwendest du display_errors = Off, log_errors = On und einen Pfad für error_log und behältst error_reporting = E_ALL, damit Probleme trotzdem aufgezeichnet werden.
Was macht error_reporting(0)?
Es schaltet die Meldung aller Fehlertypen für den Rest des Skripts ab, sodass Warnungen und sogar fatale Fehler keine Meldung erzeugen. Das versteckt Probleme, statt sie zu beheben; protokolliere Fehler lieber, statt sie stummzuschalten.