W3docs

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:

MethodeGibt 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: 42

Mehrere 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 down

Die 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 runs

Benutzerdefinierte 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-ExceptionsInvalidArgumentException, 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 zero

Als 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

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.

Übungen

Übung
Was gilt für PHP Exceptions gemäß den Informationen auf der angegebenen URL?
Was gilt für PHP Exceptions gemäß den Informationen auf der angegebenen URL?
Was this page helpful?