PHP Exceptions verstehen
PHP Exceptions ermöglichen strukturiertes Fehlerhandling. Lernen Sie throw, catch, finally und eigene Exception-Klassen in PHP kennen.
Eine Exception ist ein Objekt, das einen Fehler oder eine unerwartete Bedingung darstellt, die den normalen Ablauf des Programms unterbricht. Anstatt einen Fehlercode zurückzugeben, den der Aufrufer möglicherweise vergisst zu prüfen, „wirft" der Code eine Exception; die Laufzeitumgebung entfaltet dann den Aufrufstapel, bis sie einen passenden catch-Block findet. Wird kein Block gefunden, bricht das Skript mit einem schwerwiegenden Fehler ab.
Dieses Kapitel behandelt das Werfen und Abfangen von Exceptions, die Methoden, die jede Exception bereitstellt (getMessage(), getCode(), getLine(), getFile()), den finally-Block, mehrere catch-Blöcke, benutzerdefinierte Exception-Klassen und den Unterschied zwischen Exception und Error.
Was ist eine PHP Exception?
Eine PHP Exception ist ein Objekt, das von der eingebauten Exception-Klasse abstammt (oder allgemeiner vom Throwable-Interface). Wenn etwas schiefläuft — eine fehlende Datei, ein ungültiges Argument, eine fehlgeschlagene Datenbankverbindung — erstellen Sie eines dieser Objekte und throwen es. Das Werfen unterbricht sofort den aktuellen Ausführungspfad und übergibt die Kontrolle an den nächstgelegenen Handler.
Verwenden Sie eine Exception, wenn eine Funktion nicht sinnvoll fortfahren kann und der Aufrufer der richtige Ort ist, um zu entscheiden, was als Nächstes zu tun ist. Verwenden Sie sie nicht für gewöhnlichen Kontrollfluss (ein normales „Benutzer nicht gefunden"-Lookup wird besser durch einen Rückgabewert ausgedrückt).
Eine Exception werfen
Das throw-Schlüsselwort löst eine Exception aus, gefolgt von einer neuen Instanz einer Exception-Klasse. Der Konstruktor akzeptiert eine optionale Nachricht, einen Integer-Code und eine vorherige Exception (für Verkettung):
<?php
function divide(int $a, int $b): float
{
if ($b === 0) {
throw new InvalidArgumentException('Division by zero is not allowed.');
}
return $a / $b;
}
try {
echo divide(10, 0);
} catch (InvalidArgumentException $e) {
echo 'Error: ' . $e->getMessage();
}
?>Ausgabe:
Error: Division by zero is not allowed.Der Code innerhalb von try läuft normal, bis throw ausgelöst wird. Ab diesem Punkt wird der Rest des try-Blocks übersprungen und der passende catch-Block wird ausgeführt.
Exceptions mit try / catch behandeln
Sie umschließen Code, der fehlschlagen könnte, in einem try-Block und beheben den Fehler in einem catch-Block. Die Variable in catch (hier $e) hält das Exception-Objekt, das mehrere schreibgeschützte Methoden bereitstellt:
| Methode | Gibt zurück |
|---|---|
getMessage() | Die lesbare Nachricht |
getCode() | Den Integer-Code, der an den Konstruktor übergeben wurde |
getLine() | Die Zeile, in der die Exception geworfen wurde |
getFile() | Die Datei, in der sie geworfen wurde |
getPrevious() | Die verkettete „vorherige" Exception, falls vorhanden |
getTraceAsString() | Den Stack-Trace als String |
<?php
try {
throw new Exception('Something failed', 42);
} catch (Exception $e) {
echo 'Message: ' . $e->getMessage() . PHP_EOL;
echo 'Code: ' . $e->getCode() . PHP_EOL;
}
?>Ausgabe:
Message: Something failed
Code: 42Mehrere Exception-Typen abfangen
Ein einzelner try-Block kann mehrere catch-Blöcke haben. PHP prüft sie von oben nach unten und führt den ersten aus, dessen Typ übereinstimmt. Seit PHP 7.1 können Sie auch mehrere nicht verwandte Typen in einem Block mit dem Pipe-Operator (|) abfangen:
<?php
try {
throw new RuntimeException('Network is down');
} catch (InvalidArgumentException $e) {
echo 'Bad argument: ' . $e->getMessage();
} catch (RuntimeException | LogicException $e) {
echo 'Runtime/logic problem: ' . $e->getMessage();
}
?>Ausgabe:
Runtime/logic problem: Network is downDie Reihenfolge ist wichtig: Listen Sie spezifischere Exception-Typen vor ihren übergeordneten Klassen auf, sonst fängt der breitere catch alles zuerst ab.
Der finally-Block
Der finally-Block ist optional, aber nützlich. Sein Code wird immer ausgeführt — unabhängig davon, ob eine Exception geworfen wurde oder nicht, und selbst wenn der try- oder catch-Block ein return ausführt. Das macht ihn zum richtigen Ort für Aufräumarbeiten wie das Schließen eines Datei-Handles oder das Freigeben einer Sperre:
<?php
try {
echo 'Open resource' . PHP_EOL;
throw new Exception('Boom');
} catch (Exception $e) {
echo 'Caught: ' . $e->getMessage() . PHP_EOL;
} finally {
echo 'Cleanup always runs' . PHP_EOL;
}
?>Ausgabe:
Open resource
Caught: Boom
Cleanup always runsBenutzerdefinierte Exception-Klassen
Über die eingebauten Typen hinaus können Sie eigene Exception-Klassen definieren, indem Sie Exception erweitern. Eine benutzerdefinierte Klasse ermöglicht es Ihnen, zusätzliche Daten zu übertragen (z. B. einen fehlgeschlagenen Wert) und Aufrufern zu ermöglichen, Ihren spezifischen Fehlertyp abzufangen, ohne versehentlich nicht verwandte abzufangen:
<?php
class InsufficientFundsException extends Exception
{
private float $shortfall;
public function __construct(float $shortfall)
{
$this->shortfall = $shortfall;
parent::__construct("Short by $shortfall");
}
public function getShortfall(): float
{
return $this->shortfall;
}
}
try {
throw new InsufficientFundsException(25.5);
} catch (InsufficientFundsException $e) {
echo $e->getMessage() . PHP_EOL;
echo 'Need ' . $e->getShortfall() . ' more.';
}
?>Ausgabe:
Short by 25.5
Need 25.5 more.PHP liefert auch eine Familie vorgefertigter SPL-Exceptions — InvalidArgumentException, RuntimeException, LengthException und andere — sodass Sie oft keine eigenen erfinden müssen.
Exception vs. Error
Seit PHP 7 werden interne Engine-Fehler (wie ein Typfehler oder der Aufruf einer undefinierten Methode) als Error-Objekte geworfen, nicht als Exception-Objekte. Beide implementieren das Throwable-Interface. Ein einfaches catch (Exception $e) fängt einen Error nicht ab. Um beide zu behandeln, fangen Sie das Interface ab:
<?php
try {
$result = 10 % 0; // throws a DivisionByZeroError
} catch (Throwable $e) {
echo get_class($e) . ': ' . $e->getMessage();
}
?>Ausgabe:
DivisionByZeroError: Modulo by zeroAls Faustregel: Reservieren Sie Exception für Probleme, von denen sich Ihre Anwendung erholen kann, und lassen Sie Error Bugs repräsentieren, die Sie beheben sollten, anstatt sie abzufangen.
Verwandte Themen
- PHP Errors — der Unterschied zwischen Fehlern und Exceptions.
- PHP
try-Anweisung — ein gezielter Blick auf dastry-Konstrukt. set_exception_handler()— ein globaler Fallback für nicht abgefangene Exceptions.- PHP Klassen und Objekte — notwendig, um benutzerdefinierte Exception-Klassen zu erstellen.
- PHP Funktionen — wo Exceptions am häufigsten geworfen werden.
Fazit
Exceptions geben PHP eine strukturierte Möglichkeit, mit Fehlern umzugehen: Eine Funktion throwt, wenn sie nicht fortfahren kann, und der Aufrufer catcht, um sich zu erholen, zu protokollieren oder weiterzuwerfen. Kombinieren Sie try, catch und finally, um den Erfolgsfall von der Fehlerbehandlung und dem Aufräumen zu trennen, verwenden Sie benutzerdefinierte Klassen, um die Fehler Ihrer Domäne zu modellieren, und denken Sie daran, dass Engine-Fehler als Error ankommen (abfangbar über Throwable). Das Üben dieser Muster in Ihren eigenen Projekten wird Ihren Code erheblich robuster machen.