getPrevious()
Die PHP-Funktion getPrevious() gibt die vorherige Exception zurück, die beim Erstellen der aktuellen übergeben wurde. Alles über Exception-Chaining.
Einführung
Exception::getPrevious() gibt die Exception zurück, die als drittes Argument an einen PHP-Exception-Konstruktor übergeben wurde — also die Exception, die die aktuelle verursacht hat. Sie ist in der Basisklasse Exception (und Error) definiert, sodass jeder PHP-Exception-Typ sie erbt.
Diese Seite erklärt, was getPrevious() zurückgibt, wie man eine Kette von „gewrappten" Exceptions aufbaut, wie man diese Kette durchläuft und welche häufigen Fehler zu vermeiden sind.
Syntax und Rückgabewert
final public Throwable::getPrevious(): ?Throwable- Parameter: keine.
- Rückgabe: das vorherige
Throwable(eineExceptionoder einError), sofern eines gesetzt wurde, andernfallsnull. - Die Methode ist
final, kann also nicht in eigenen Exception-Unterklassen überschrieben werden.
Die „vorherige" Exception wird gesetzt, wenn eine Exception mit einem dritten Argument erzeugt wird:
throw new RuntimeException("High-level failure", 0, $originalException);
// message ^code ^previousEinfaches Beispiel
Wenn eine Exception erneut geworfen wird, sollte die ursprüngliche als drittes Konstruktorargument übergeben werden, damit der Kontext nicht verloren geht:
<?php
try {
try {
throw new Exception("Inner error");
} catch (Exception $inner) {
// Wrap the low-level error in a more meaningful one,
// keeping the original as "previous".
throw new Exception("Outer error", 0, $inner);
}
} catch (Exception $e) {
echo "Caught: " . $e->getMessage() . "\n";
$previous = $e->getPrevious();
if ($previous !== null) {
echo "Caused by: " . $previous->getMessage() . "\n";
}
}
?>Ausgabe:
Caught: Outer error
Caused by: Inner errorgetPrevious() gibt das übergebene $inner-Objekt zurück, sodass dessen Nachricht, Code oder Stack-Trace genauso ausgelesen werden können wie bei jeder anderen Exception.
Warum Exceptions überhaupt wrappen?
Ein verbreitetes Muster ist, eine technische Low-Level-Exception (z. B. eine fehlgeschlagene Datenbankabfrage, eine fehlende Datei) abzufangen und eine domänenspezifische High-Level-Exception zu werfen — ohne dabei die ursprüngliche Ursache zu verwerfen:
<?php
function loadUser(int $id): array
{
try {
// Pretend this talks to a database and fails.
throw new RuntimeException("SQLSTATE[HY000]: connection refused");
} catch (RuntimeException $dbError) {
// Callers care about "could not load user", not SQL internals,
// but we keep the SQL error available via getPrevious().
throw new RuntimeException("Unable to load user #$id", 0, $dbError);
}
}
try {
loadUser(42);
} catch (RuntimeException $e) {
echo $e->getMessage() . "\n";
echo "Root cause: " . $e->getPrevious()->getMessage() . "\n";
}
?>Ausgabe:
Unable to load user #42
Root cause: SQLSTATE[HY000]: connection refusedSo bleiben High-Level-Fehlermeldungen übersichtlich, während technische Details für Logging und Debugging erhalten bleiben.
Die vollständige Exception-Kette durchlaufen
Eine vorherige Exception kann selbst eine vorherige Exception haben. Um die gesamte Kette zu untersuchen, wird solange eine Schleife ausgeführt, wie getPrevious() einen Nicht-null-Wert zurückgibt:
<?php
$a = new Exception("Level 1: low-level cause");
$b = new Exception("Level 2: mid-level wrapper", 0, $a);
$c = new Exception("Level 3: top-level error", 0, $b);
$current = $c;
while ($current !== null) {
echo $current->getMessage() . "\n";
$current = $current->getPrevious();
}
?>Ausgabe:
Level 3: top-level error
Level 2: mid-level wrapper
Level 1: low-level causeHäufige Fallstricke
- Keine vorherige Exception ergibt
null. Wird eine Exception ohne drittes Argument erzeugt, gibtgetPrevious()nullzurück. Vor dem Aufruf von Methoden auf dem Ergebnis immer mit!== null(oder einer Schleife) prüfen. - Das dritte Konstruktorargument ist die vorherige Exception, nicht der Code. Die Signatur lautet
new Exception($message, $code, $previous). Ein häufiger Fehler ist, die vorherige Exception an zweiter Stelle zu übergeben, wo PHP einen Integer-Code erwartet. - Es ist schreibgeschützt. Es gibt kein
setPrevious(). Die Kette wird zur Konstruktionszeit festgelegt; die Ursache muss also beim Erstellen der wrappenden Exception übergeben werden. var_dump($e)zeigt die Kette bereits an. Wird eine nicht abgefangene Exception in einen string umgewandelt (oder von PHP ausgegeben), wird die „Caused by"-/Vorgänger-Exception-Spur automatisch einbezogen —getPrevious()ist für den Fall gedacht, dass die Kette im Code untersucht werden soll.
Verwandte Methoden
getPrevious() ist eine von mehreren Inspektionsmethoden, die jede PHP-Exception bereitstellt:
getMessage()— die lesbare Fehlermeldung.getCode()— der numerische Fehlercode.getTrace()— der Stack-Trace als array.getTraceAsString()— der Stack-Trace als string.
Einen umfassenden Überblick über try/catch und benutzerdefinierte Exception-Klassen bietet PHP Exceptions.
Zusammenfassung
getPrevious() gibt die Exception zurück, die die aktuelle verursacht hat, und ermöglicht so Exception-Chaining: eine Low-Level-Exception abfangen, eine aussagekräftige High-Level-Exception werfen und dabei die ursprüngliche Ursache für das Debugging bewahren. Wurde keine vorherige Exception gesetzt, gibt die Methode null zurück — darauf sollte vor der Verwendung des Ergebnisses geprüft oder eine Schleife verwendet werden.