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";
}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"));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";
}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();gefangen: Undefined variable $nicht_definiert
Merke
try / catch / finally,throw new ...Throwable->ExceptionundError- Eigene Exception-Klassen für sinnvolle Fehlerarten
getPrevious()verkettet Ursachen;throwist ein Ausdruck (?? throw)- Fehlermeldungen in Produktion loggen, nicht anzeigen
set_error_handlerwandelt Warnungen in Exceptions um
Aufgabe
Schreibe parseAlter(string $s): int, das bei ungültigem Text eine eigene Exception wirft, und fange sie ab.