Navigation
 Startseite
 Fachbücher
 Anzeigenmarkt
 Forum
 Webmaster News
 Script Newsletter
 Push Meldungen
 Kontakt
 Script Installation
 Php
 Php Tutorials
 Lernpfade
 Webhoster Vergleich
 Impressum

Community-Bereich
 kostenlos Registrieren
 Anmelden
 Benutzerliste

Script Datenbank
 Script Archiv
 Script Top 20
 Screenshots
 Testberichte

Suche
 

Unsere Php Scripts
 Counter Script
 Umfrage Script
 Bilder Upload Script
 Terminverwaltung
 Simple PHP Forum
 RSS Grabber

Tools und Generatoren
 .htpasswd Generator
 md5 Generator
 base64 Generator
 Markdown to HTML
 Colorpicker
 Unix timestamp Tool
 Unit Test Generator
 TLD Liste
 Webkatalog‑Verzeichnis

Webspace-Mieten.d...
Webhosting mit Plesk aus Erfurt: Vier...
https://www.Webspace-Mieten.de
Hosterplus.de
Bekommen Sie Speicherplatz (Webspace), Domains...
https://www.Hosterplus.de
 
 
 

PHP set_error_handler(): Error Handling mit ErrorException

Sie befinden sich: Home > Php Tutorial > PHP set_error_handler(): Er...

PHP set_error_handler(): Error Handling mit ErrorException
Veröffentlicht am:
16.10.2026
Hits / Besucher:
7
Sprache:
  Deutsch
Tutorial Art:
eigenes
Eingetragen von:
Merkliste:
 
Beschreibung

Ein nächtlicher Import liest eine CSV-Datei, die an diesem Tag fehlt. Um den Aufruf steht ein try-Block, und trotzdem greift kein catch. PHP schreibt eine Warnung ins Protokoll, $inhalt ist false, und das Skript importiert munter null Datensätze. Mit PHP set_error_handler lässt sich genau das ändern: Die Funktion leitet Warnungen, Hinweise und Deprecations an eigenen Code weiter, der sie zum Beispiel in eine ErrorException verwandelt. Danach fängt der catch-Block, was er fangen soll.

Illustration zum Tutorial: PHP set_error_handler(): Error Handling mit ErrorException

Der Handler ist die Weiche zwischen beiden Welten. Was er nicht selbst erledigt, geht weiter an die Standardbehandlung von PHP.

Warum try/catch keine Warnung fängt

PHP kennt zwei getrennte Fehlersysteme. Das ältere arbeitet mit Meldungen, die eine Fehlerstufe tragen: E_WARNING, E_NOTICE, E_DEPRECATED und so weiter. Das neuere arbeitet mit Ausnahmen. Ein catch reagiert nur auf Ausnahmen, an einer Warnung läuft er vorbei:

<?php

try {
$inhalt = file_get_contents('daten.csv');
} catch (Exception $e) {
echo 'Wird nie erreicht.';
}
var_dump($inhalt); /* bool(false) */

/* Warning: file_get_contents(daten.csv):
Failed to open stream: No such file
or directory */

Manche Erweiterungen werfen inzwischen selbst, mysqli zum Beispiel seit PHP 8.1, nachzulesen im Tutorial zu mysqli_errno() und Ausnahmen. Viele Dateifunktionen melden sich dagegen weiterhin nur mit einer Warnung. Für sie schlägt PHP set_error_handler die Brücke zwischen beiden Welten.

Die Signatur von PHP set_error_handler()

<?php

set_error_handler(
?callable $callback,
int $error_levels = E_ALL
): ?callable

restore_error_handler(): true

/* Signature of the callback */
handler(
int $errno,
string $errstr,
string $errfile,
int $errline
): bool

/*
* $callback Called for every error that
* matches $error_levels.
* null restores PHP's default.
* $error_levels Bitmask of error types passed
* to the handler (default E_ALL).
* Return value The previous handler or null.
* Callback returns false: PHP's standard
* error handler runs as well.
*/

Der Rückgabewert von PHP set_error_handler ist der Handler, der vorher aktiv war, beim ersten Aufruf also null. Wichtiger für den Alltag ist der Rückgabewert der Rückruffunktion selbst, denn er entscheidet, ob PHP die Meldung zusätzlich ausgibt. Darum geht es im nächsten Abschnitt.

Der Error Handler und sein Rückgabewert

Die Rückruffunktion bekommt vier Werte: die Fehlerstufe als Zahl, den Meldungstext, die Datei und die Zeile. Ein fünfter Parameter $errcontext ist mit PHP 8.0 entfallen. Alte Beispiele, die ihn als Pflichtparameter erwarten, enden heute mit ArgumentCountError: Too few arguments, sobald die erste Warnung auftritt. Ein minimaler Handler für PHP set_error_handler gibt die Werte einfach aus:

<?php

set_error_handler(function (
int $errno,
string $errstr,
string $errfile,
int $errline
): bool {
echo "[$errno] $errstr in Zeile $errline\n";
return true;
});

echo $nichtDa;
/* [2] Undefined variable $nichtDa in Zeile 12 */

Der Rückgabewert des Handlers ist bei PHP set_error_handler der heikelste Punkt. Nur false lässt die Standardbehandlung weiterlaufen: Die Warnung erscheint zusätzlich, und error_get_last() ist gefüllt. Jeder andere Wert gilt als erledigt. Gemessen gilt das für true, für 0 und auch für einen Handler ganz ohne return. Wer das return vergisst und im Handler selbst nichts ausgibt, verschluckt also still jede Meldung. Dazu kommt: Ein mit PHP set_error_handler registrierter Handler läuft auch dann, wenn error_reporting auf 0 steht. Die Prüfung der Maske ist Aufgabe des Handlers. Den Weg einer Meldung durch diese Weichen zeigt das Diagramm.

flowchart TD
    A[Meldung ausgelöst] --> B{Fatal oder Parse?}
    B -- ja --> C[kein Handler]
    C --> D[Shutdown-Funktion]
    B -- nein --> E{in error_levels?}
    E -- nein --> F[Standardbehandlung]
    E -- ja --> G[Handler aufgerufen]
    G --> H{Rückgabe false?}
    H -- ja --> F
    H -- nein --> I[erledigt]
    G -. wirft ErrorException .-> J[try/catch]

Warnungen in eine ErrorException umwandeln

Der Handler prüft zuerst, ob die Meldung laut aktueller Maske überhaupt gemeldet werden soll, und wirft sonst eine ErrorException. Diese Klasse hat genau die Felder, die der Handler mitbringt: Meldung, Code, Schweregrad, Datei und Zeile. Der try-Block aus der Einleitung funktioniert damit ohne jede Änderung, nur der catch nennt jetzt die passende Klasse.

<?php

set_error_handler(function (
int $errno,
string $errstr,
string $errfile,
int $errline
): bool {
if (!(error_reporting() & $errno)) {
return false;
}
throw new ErrorException(
$errstr, 0, $errno, $errfile, $errline
);
});

try {
$inhalt = file_get_contents('daten.csv');
} catch (ErrorException $e) {
echo $e->getSeverity(); /* 2 = E_WARNING */
echo $e->getMessage();
}
var_dump(isset($inhalt)); /* bool(false) */

Die letzte Zeile zeigt den eigentlichen Nutzen. Die Zuweisung an $inhalt findet gar nicht statt, der Code läuft also nicht mit false weiter, als wäre nichts gewesen. Die Fehlerstufe steht in getSeverity(), getCode() bleibt 0. Fängt niemand die Ausnahme, endet das Skript mit Fatal error: Uncaught ErrorException, und das ist bei einem Import, der sonst leere Daten schreiben würde, das bessere Ende.

Der @-Operator und error_reporting() im Handler

Die Prüfzeile mit dem bitweisen Und hat einen zweiten Zweck: Sie respektiert den Unterdrückungsoperator @. Vor PHP 8 lieferte error_reporting() innerhalb des Handlers bei einem unterdrückten Aufruf 0, daher stammt die Prüfung auf === 0 in vielen alten Beispielen. Seit PHP 8 kommt dort 4437 heraus, die Summe der Stufen, die sich nicht unterdrücken lassen. Ein Vergleich mit 0 schlägt also nie mehr an.

<?php

error_reporting(E_ALL);
set_error_handler(function (int $no, string $s): bool {
echo error_reporting(), "\n";
return true;
});

file_get_contents('fehlt.txt'); /* Maske */
@file_get_contents('fehlt.txt'); /* 4437 */

Ohne @ erscheint die eingestellte Maske, hier der Wert von E_ALL, der sich je nach Konfiguration und PHP-Version unterscheidet. Die 4437 ist dagegen fest. Mit der Zeile if (!(error_reporting() & $errno)) { return false; } liefert @file_get_contents() auf eine fehlende Datei weiterhin still false, ohne Ausnahme. So bleibt jedes bewusst gesetzte @ wirksam, auch mit eigenem Handler.

restore_error_handler(): den vorigen Handler zurückholen

Handler liegen auf einem Stapel. Jeder Aufruf von PHP set_error_handler legt einen neuen obendrauf, restore_error_handler() nimmt den obersten wieder herunter. Ein Versuch mit zwei Handlern A und B zeigt es: Eine Warnung landet erst bei B, nach einem restore_error_handler() bei A und nach einem zweiten bei der Standardbehandlung. set_error_handler(null) stellt die Standardbehandlung ebenfalls her.

Der Rückgabewert von restore_error_handler() ist immer true, auch bei acht Aufrufen auf einem leeren Stapel. Als Kontrolle taugt er nicht, überzählige Aufrufe fallen nicht auf. Umso wichtiger ist, dass Setzen und Zurücknehmen fest zusammengehören. Das sicherste Muster dafür ist finally, denn es läuft auch dann, wenn der Code dazwischen eine Ausnahme wirft. Ohne finally bliebe der temporäre Handler genau in diesem Fall aktiv.

<?php

$hinweise = [];
$sammler = function (int $no, string $s)
use (&$hinweise): bool {
$hinweise[] = $s;
return true;
};
set_error_handler(
$sammler,
E_DEPRECATED | E_USER_DEPRECATED
);

try {
$export = altbibliothek_export($daten);
} finally {
restore_error_handler();
}

Die Altbibliothek erzeugt Deprecations, die im eigenen Protokoll nur stören. Sie landen gesammelt in $hinweise, und nach dem Block gilt wieder der Handler, den der vorige Aufruf von PHP set_error_handler gesetzt hatte. Wirft altbibliothek_export() eine Ausnahme, wird trotzdem zurückgesetzt.

Nur bestimmte Fehlerarten abfangen

Der zweite Parameter $error_levels ist ein Filter. Mit E_NOTICE | E_USER_NOTICE geht eine E_WARNING gemessen an der Funktion vorbei direkt in die Standardbehandlung. Für verschiedene Fehlerarten lässt sich aber kein zweiter Handler parallel registrieren. Ein neuer Aufruf von PHP set_error_handler ersetzt den aktiven, er ergänzt ihn nicht. Wer unterschiedliche Fehlerarten unterschiedlich behandeln will, verzweigt deshalb in einem einzigen Handler, am elegantesten mit match:

<?php

set_error_handler(function (
int $errno,
string $errstr,
string $errfile,
int $errline
): bool {
if (!(error_reporting() & $errno)) {
return false;
}
return match ($errno) {
E_DEPRECATED,
E_USER_DEPRECATED => error_log("Alt: $errstr"),
E_WARNING,
E_USER_WARNING => throw new ErrorException(
$errstr, 0, $errno, $errfile, $errline
),
default => false,
};
});

Deprecations werden nur festgehalten, error_log() liefert dabei true und meldet sie damit als erledigt. Warnungen werden zur Ausnahme. Alles andere, etwa ein Hinweis aus trigger_error() mit E_USER_NOTICE, geht über false an die Standardbehandlung. Wohin die Meldung danach geschrieben wird und wie man das konfiguriert, steht im Tutorial zu error_log(). Hier geht es darum, wie die Meldung überhaupt im eigenen Code ankommt. Für eigene Testmeldungen eignen sich E_USER_WARNING und E_USER_NOTICE. E_USER_ERROR an trigger_error() zu übergeben, löst seit PHP 8.4 selbst eine Deprecation aus.

Klassenmethode als Error Handler

In größeren Anwendungen steckt der Handler meist in einer Klasse. PHP set_error_handler nimmt jede Form von callable: eine Closure, ein Array aus Objekt und Methodenname, eine statische Methode oder seit PHP 8.1 die First-Class-Callable-Syntax.

<?php

final class FehlerWandler
{
public function behandle(
int $errno,
string $errstr,
string $errfile,
int $errline
): bool {
throw new ErrorException(
$errstr, 0, $errno, $errfile, $errline
);
}
}

$wandler = new FehlerWandler();
set_error_handler($wandler->behandle(...));
/* gleichwertig: [$wandler, 'behandle'] */

Ein Detail für jede Form: Eine Warnung, die im Handler selbst entsteht, geht gemessen nicht erneut an den Handler, sondern an die Standardbehandlung. Funktionen, die selbst warnen können, gehören deshalb nur mit Bedacht in den Handler.

Grenzen des Error Handling: welche Fehler kein Handler sieht

PHP set_error_handler fängt nicht alle Fehler, und wer das annimmt, hält seinen Handler schnell für defekt. Fatale Fehler, Parse-Fehler und die Kern- und Compilerfehler erreichen ihn nie, weil PHP an dieser Stelle keinen eigenen Code mehr sicher ausführen kann. Daneben gibt es Fehler, die seit PHP 7 als Ausnahme der Klasse Error geworfen werden. Sie sind keine Meldungen mit Fehlerstufe und laufen deshalb am Error Handler vorbei, lassen sich aber mit try/catch fangen.

Fehlerart Beispiel Erreicht den Handler? Ausweg
E_WARNING fehlende Datei, Undefined variable, Undefined array key, A non-numeric value encountered ja ErrorException werfen
E_NOTICE, E_DEPRECATED, alle E_USER_* veraltete Funktion, trigger_error() ja festhalten oder werfen
E_ERROR Allowed memory size exhausted nein Shutdown-Funktion mit error_get_last()
E_PARSE Syntaxfehler im aufgerufenen Skript nein bei include: ParseError fangen
E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING Fehler beim Start von PHP oder beim Kompilieren nein Server-Protokoll lesen
Error-Ausnahmen Call to undefined function, DivisionByZeroError bei 1 % 0 nein catch (Error $e) oder Throwable

Für den echten Absturz bleibt nur ein Blick nach dem Ende. register_shutdown_function() läuft auch nach einem fatalen Fehler, und error_get_last() liefert dort Typ und Meldung. Gemessen mit einem zu knappen memory_limit: Der Error Handler schweigt, die Shutdown-Funktion sieht Typ 1 und den Text Allowed memory size of 8388608 bytes exhausted.

<?php

register_shutdown_function(function (): void {
$fehler = error_get_last();
if ($fehler === null) {
return;
}
if ($fehler['type'] === E_ERROR) {
error_log('Absturz: ' . $fehler['message']);
}
});

set_error_handler() und set_exception_handler()

Die Namen klingen ähnlich, die Aufgaben sind verschieden. Der mit PHP set_error_handler registrierte Handler sieht Meldungen mit Fehlerstufe, und zwar sofort, an der Stelle, an der sie entstehen. Der Exception Handler aus set_exception_handler() sieht nur Ausnahmen, die niemand gefangen hat, und zwar ganz am Ende, kurz bevor das Skript abbricht. Beide arbeiten zusammen: Eine ErrorException, die der Error Handler wirft und kein catch abfängt, landet als nicht gefangene Ausnahme beim Exception Handler.

Fazit

Warnungen sind in PHP keine Ausnahmen, und ein try/catch allein fängt sie nicht. PHP set_error_handler schließt diese Lücke mit wenigen Zeilen: Maske prüfen, damit das @ wirkt, dann eine ErrorException werfen. Ein guter Handler endet mit einem bewussten return, weil nur false die Standardbehandlung weiterlaufen lässt. Und wer ihn nur vorübergehend setzt, nimmt ihn im finally mit restore_error_handler() wieder zurück. Fatale Fehler bleiben draußen, für sie gibt es die Shutdown-Funktion.

 

Tags:

 

 

Kommentare (0)

Noch keine Kommentare. Sei der Erste!

Melde dich an, um einen Kommentar zu schreiben.
Bücherregal mit drei Büchern: 'PHP 4 - Grundlagen und Profiwissen' von Hanser Verlag, 'Webdesign in a Nutshell' von O'Reilly Verlag, und 'Webgestaltung' von Galileo Computing.