Baue eine vollständige Fehlerstrategie: verkettete fachliche Exceptions, kontrolliertes finally und globale Handler als letzte Verteidigungslinie.
Diese Lektion in Kodokon öffnenSeit PHP 7 implementiert alles, was geworfen wird, Throwable, mit zwei Zweigen: Error (Fehler der Engine und der Typisierung, wie TypeError) und Exception (Fehler der Anwendung). Error fängst du nur an den Grenzen des Programms. Auf Anwendungsseite liefert die SPL eine fertige Hierarchie: LogicException signalisiert einen Entwicklerfehler, der behoben werden muss; RuntimeException einen Zwischenfall zur Laufzeit, der behandelt werden muss. Der professionelle Reflex: Leite deine fachlichen Exceptions von diesen Basen ab, eine pro erkennbarer Situation.
<?php
declare(strict_types=1);
abstract class AppException extends RuntimeException
{
}
final class UserNotFound extends AppException
{
public static function withEmail(
string $email
): self {
return new self("No user for $email");
}
}
try {
throw UserNotFound::withEmail('lea@example.com');
} catch (UserNotFound $e) {
echo $e->getMessage();
}try/catch lohnt sich nur, wenn du weißt, was du mit dem Fehler anfangen sollst - andernfalls lass ihn nach oben durchreichen. Drei Werkzeuge verfeinern die Kontrolle: Das Multi-Catch catch (JsonException | ValueError $e) fasst identische Behandlungen zusammen; der Parameter previous verkettet die ursprüngliche Ursache, wenn du eine technische Exception in eine fachliche übersetzt; finally läuft in jedem Fall - Erfolg, Exception, sogar bei einem vorzeitigen return - ideal, um eine Ressource freizugeben.
<?php
declare(strict_types=1);
final class PayloadInvalid extends RuntimeException
{
}
function decode(string $json): mixed
{
try {
return json_decode(
$json,
true,
flags: JSON_THROW_ON_ERROR,
);
} catch (JsonException $e) {
throw new PayloadInvalid(
'Invalid JSON payload',
previous: $e,
);
} finally {
echo "decode() finished\n";
}
}
try {
decode('{broken');
} catch (PayloadInvalid $e) {
echo $e->getPrevious()?->getMessage();
}Am Ende der Kette schließen zwei globale Handler das Ganze ab. set_exception_handler fängt alles ab, was nicht behandelt wurde: strukturiertes Logging, eine generische 500-Antwort - ohne jemals die Nachricht oder den Trace an den Nutzer preiszugeben. set_error_handler wandelt die alten Fehler (Warnings, Notices) in ErrorException um und vereinheitlicht so die beiden Welten: Alles wird zur Exception, alles folgt demselben Behandlungsweg.
<?php
declare(strict_types=1);
set_error_handler(function (
int $severity,
string $message,
string $file,
int $line,
): bool {
throw new ErrorException(
$message,
0,
$severity,
$file,
$line,
);
});
set_exception_handler(function (Throwable $e): void {
error_log($e->getMessage());
http_response_code(500);
echo 'A technical error occurred.';
});
trigger_error('Legacy warning', E_USER_WARNING);
echo 'Never reached';Error und Exception im modernen PHP gemeinsam?Error erbt von ExceptionThrowablefinally-Block?previous einer Exception da?