EMZETT.
Login

Kurz: try { echo teile(10, 4), “\n”; echo teile(1, 0), “\n”; echo “nicht erreicht\n”; } catch (DivisionByZeroError e) { echo "Fehler: ", e->getMessage(), “\n”; } finally { echo “finally läuft immer\n”; } “ `output 2.5 Fehler.

Teil des Kurses PHP

Kapitel 9 von 15 im Kurs PHP. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Exceptions

<?php
function teile(float $a, float $b): float
{
    if ($b == 0) {
        throw new DivisionByZeroError("Division durch null");
    }
    return $a / $b;
}
 
try {
    echo teile(10, 4), "\n";
    echo teile(1, 0), "\n";
    echo "nicht erreicht\n";
} catch (DivisionByZeroError $e) {
    echo "Fehler: ", $e->getMessage(), "\n";
} finally {
    echo "finally läuft immer\n";
}

Ausgabe:

2.5
Fehler: Division durch null
finally läuft immer

Hierarchie

Throwable ist die Basis; sie teilt sich in Exception (zu behandelnde Fehler) und Error (Programmierfehler wie TypeError, ValueError).

<?php
function versuche(callable $f): void
{
    try { $f(); }
    catch (TypeError | ValueError $e) { echo get_class($e), ": ", $e->getMessage(), "\n"; }
    catch (Throwable $e) { echo "anderes: ", get_class($e), "\n"; }
}
versuche(fn() => strlen([]));
versuche(fn() => str_repeat("x", -1));
versuche(fn() => intdiv(1, 0));
versuche(fn() => abs("keine zahl"));
versuche(fn() => new DateTime("kein datum"));

Ausgabe:

TypeError: strlen(): Argument #1 ($string) must be of type string, array given
ValueError: str_repeat(): Argument #2 ($times) must be greater than or equal to 0
anderes: DivisionByZeroError
TypeError: abs(): Argument #1 ($num) must be of type int|float, string given
anderes: DateMalformedStringException

Eigene Exceptions

<?php
class AppException extends Exception {}
class NichtGefunden extends AppException
{
    public function __construct(private string $was, ?Throwable $vorher = null)
    {
        parent::__construct("{$was} nicht gefunden", 404, $vorher);
    }
    public function was(): string { return $this->was; }
}
 
function suche(array $db, string $key): string
{
    return $db[$key] ?? throw new NichtGefunden($key);     // throw als Ausdruck (8.0)
}
 
try {
    echo suche(["a" => "Apfel"], "a"), "\n";
    echo suche(["a" => "Apfel"], "b"), "\n";
} catch (AppException $e) {
    echo get_class($e), " ", $e->getCode(), " ", $e->getMessage(), "\n";
}
 
try {
    try {
        throw new RuntimeException("innen");
    } catch (RuntimeException $e) {
        throw new LogicException("außen", 0, $e);           // Ursache verketten
    }
} catch (LogicException $e) {
    echo $e->getMessage(), " <- ", $e->getPrevious()->getMessage(), "\n";
}

Ausgabe:

Apfel
NichtGefunden 404 b nicht gefunden
außen <- innen

Warnungen, Notices und Fehlerlevel

Neben Exceptions gibt es klassische Meldungen (Warning, Notice, Deprecated). Zeige sie in der Entwicklung an, im Betrieb nur ins Log:

<?php
error_reporting(E_ALL);
ini_set('display_errors', '0');          // nie Fehler im Browser zeigen (Produktion)
ini_set('log_errors', '1');
 
set_error_handler(function (int $nr, string $msg) {
    throw new ErrorException($msg, 0, $nr);       // Warnungen in Exceptions umwandeln
});
 
try {
    echo $nicht_definiert;
} catch (ErrorException $e) {
    echo "gefangen: ", $e->getMessage(), "\n";
}
restore_error_handler();

Ausgabe:

gefangen: Undefined variable $nicht_definiert

Merke

  • try / catch / finally, throw new ...
  • Throwable -> Exception und Error
  • Eigene Exception-Klassen für sinnvolle Fehlerarten
  • getPrevious() verkettet Ursachen; throw ist ein Ausdruck (?? throw)
  • Fehlermeldungen in Produktion loggen, nicht anzeigen
  • set_error_handler wandelt Warnungen in Exceptions um

Übungsaufgabe

Schreibe parseAlter(string $s): int, das bei ungültigem Text eine eigene Exception wirft, und fange sie ab.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Vererbung, Interfaces und Traits

Weiter: Dateien, JSON, Datum und reguläre Ausdrücke

Alle Kapitel: PHP im Überblick