x

Einloggen

Hast du noch keinen Account? Jetzt registrieren!

Wie man richtig mit Exceptions unter PHP umgeht

Zur automatisierten Fehlerbewältigung lassen sich bekannterweise bestens Exception einsetzen:


  1. Exception ist eine flexible erweiterbare Methode zur Fehlerbearbeitung

  2. Dies ist ein standardisierter Automatismus: einer, der noch nie mit deinem Code gearbeitet hat, muss nicht unbedingt ein Manual lesen, um zu begreifen, wie man die Fehler bearbeitet. Es genügt, wenn er weiß, wie Exceptions funktionieren

  3. Mit einer Excention lässt sich eine Fehlerursache viel schneller und einfacher ermitteln, da das Trace immer vorhanden ist.


Gleich zu bemerken: ich will nicht das Amerika neu entdecken. Beschrieben werden standardisierte Prinzipien einer Exception plus einige Besonderheiten, die sich auf die PHP-Programmierung beziehen. Nützlich wäre es vor Allem für Anfänger, aber auch erfahrene Entwickler könnten hier einige Anregungen für sich finden.

1. Wirf niemals eine abstrakte Exception (d.h. eine einfache Exception). Definiere mindest eine Exception-Klasse speziell für deine Anwendung (Modul, Bibliothek)
class baseException extends Exception{}

und ersetze alle Zeilen in deinem Code
throw new Exception();

durch
throw new baseException();

Dadurch lässt sich die Exceptions deines Codes von den Exceptions des fremden Codes unterscheiden.

2. Exception muss hierarchisch aufgebaut werden. Du musst ein Base-Exception festlegen, von dem alle in deinem Code geworfenen Exceptions abgeleitet werden. Wenn du z.B. ein fileModule hast, definiere Exceptions, die nur von diesem Modul geworfen werden.
class fileModuleException extends baseException{}

Falls du noch größere Fehlerdifferenzierung brauchst, z.B. unter allen fileModule-Fehlern nur die Situationen zu erkennen, wenn die Datei nicht gefunden wurde, musst du noch eine gesonderte Exception definieren:
class fileNotFoundException extends fileModuleException{}

Wenn du Exceptions hierarchisch aufbaust, kannst du Exceptions verschiedener Module in deiner Anwendung auseinander halten. Auf keinen Fall appelliere ich zum Erzeugen eines Haufens von Exceptions für jedes Modul. Exceptions müssen nicht vom Code her entwickelt werden, sondern eher von der Situation her, die du besonders darstellen willst. Und andersrum, musst du nicht an unterschiedlichen Exceptions sparen, wenn es notwendig ist.
try{
//...
}catch(fileModuleException $e){
switch($e->getCode()){//so sollte man nicht machen
case 1: echo 'file not found';
case 2: echo 'file not readable';
//...
}
}

Damit solche Situationen im Prinzip nicht möglich sind, kannst du den Code „abspecken“:
function __construct($message = '', $code = 0) {
parent::__construct($message, 0);
}


3. Bearbeite die Exceptions nicht, wenn es im Kontext nicht klar ist, wie sie zu bearbeiten sind.
Wenn du z.B. dem Pattern MVC folgst, kann es passieren, dass es aus der Methode nicht klar ist, wie der Fehler zu bearbeiten ist: wie er auszuführen ist, weil für die Logik „control“ zuständig ist, und für die Ausführung „view“. Wenn es nicht klar ist, was mit der Exception an der Stelle zu tun ist, gib sie einfach weiter.
try{
$db->begin();
//...
$db->commit();
}catch(Exception $e){
$db->rollback();
throw $e;
}

Von der Methode, die Exceptions wirft, kann man jegliche Exceptions erwarten. Die Zahl der geworfenen Exceptions kann verringert werden, indem die Exception verändert wird:
try{
//...
}catch(Exception $e){
throw new baseException($message, 0, $e);//die Kette bitte nicht unterbrechen
}

Der wichtige Punkt hier ist: die Kette darf nicht unterbrochen werden. Durch den dritten Parameter wird die Base Exception weidergegeben. Dieser Code arbeitet native unter 5.3 und mit einer kleinen Korrektur auch unter 5.2. Bei dieser Vorgehensweise läuft das Trace vom aller ersten Throw ab „durchgehend“.

4. Du brauchst einen Exception Handler. Dies kann „try...catch“ auf dem obersten Level sowohl auch ExceptionHandler sein. Alle Exceptions, die bis zum ExceptionHandler geschafft haben, gelten als kritisch, da sie nicht richtig bearbeitet werden konnten. Sie müssen geloggt werden!

5. Eine Exception ist ein Objekt und kann deswegen nach Bedarf erweitert werden. Nehmen wir an, du hast eine mehrsprachige Anwendung und die Fehlermeldung aus der geworfenen Exception muss dem Benutzer sichtbar gemacht werden. Selbstverständlich muss die Meldung übersetzt werden. Es ist nicht schwer, wenn die Meldung keine Variablen enthält, z.B. „Fehler beim Operationsausführen“. Problematischer ist es bei den Meldungen mit Variablen, z.B. „Sie haben nicht genug Geld auf Ihrem Konto (1000). Sie brauchen mindestens 2000“. Dann können der Fehlermeldungstext und die Variablen getrennt werden und müssen je nach Sprache unterschiedlich zusammengestellt werden.

6. Wandle alle Assertionsfehler (assertion fails) und Warnungen in Exceptions um.

7. Fang niemals Exceptions ohne Bearbeitung ab
try {
//...
} catch (Exception $e) {
//nichts mehr machen
}

da sonst der Fehler durch die Vorgehensweise nur noch zu schwer zu finden ist. Es muss mindestens geloggt werden:
try {
//...
} catch (Exception $e) {
exceptionHandlerClass::exceptionLog($e);
}


8. Dokumentiere Exceptions. Gib in der Dokumentation an, welche Exceptions von der Methode geworfen werden (Tag @throws, darf auch mehrmals angegeben werden). Das macht jedem das Leben einfacher. Im Prinzip ist das alles, was man über Exceptions wissen muss. Und zum Schluss noch ein interessanter Fakt: Exceptions können auch an Interface-Implementierungen abgefangen werden:
interface iException{}
class customException extends baseException implements iException{}
try{
//...
}catch(iException $e){
//...
}

421 Mal gelesen
+3
2. Aug 2010, 14:23

Kommentare

(0)
RSS

Kommentieren

Fett Kursiv Unterstrichen Durchgestrichen   Link Zitieren Code
Ich bin mit den Nutzungsbedingungen einverstanden.
Zukünftige Kommentare zu diesem Beitrag abonnieren (abbestellbar).
 
Bitte klicke jetzt auf den Bestätigungslink in deiner E-Mail.