| E_STRICT-kompatibler Code (Previous) | (Next) Best practices | ||||
| |
|||||
|
|||||
Ein Fehler ist definiert als ein unerwartet, nicht korrekter Programmzustande, der nicht wieder behoben werden kann. Zur Vereinfachung dieser Definition gilt, dass die Behebung des Fehlers nicht innerhalb einer Methode möglich ist. Eine unvollständige Behebung gilt trotzdem als Behebung.
Beispiel 3-1. Eine typische Fehlersituation
|
In diesem Beispiel soll die Methode die Verbindung mit der Datenbank mit dem gegegebenem DSN herstellen. Die Methode ruft ihrerseits nur PEAR::DB, wenn dieses Package einen Fehler wirft, kann nur eine Exception erzeugt und geworfen werden, ohne weiter Einfluß nehmen zu können.
Beispiel 3-2. Fehlerbehandlung mit Behebung
|
Das zweite Beispiel zeigt, wie eine Exception empfangen und behandelt wird. Die verwendete connectDB()-Methode kann nur einen Fehler melden, wenn die Verbindung fehlschlägt. Die übergeordnete Methode connect() hingegen weiss, dass das Objekt auch mit einer der anderen Datenbank-Verbindungen lauffähig ist. Deshalb kann der Fehler als behoben angesehen werden und die Exception wird nicht weitergeleitet.
Beispiel 3-3. Unvollständige Behebung
|
Die Fehlerbehebung führt zu Seiteneffekten, deshalb ist sie nicht vollständig. Das Programm kann weiterlaufen, die Exception gilt als behandelt und muss nicht weitergeleitet werden. Wie im vorherigen Beispiel sollte die aufgetretene Exception aber trotzdem geloggt werden oder eine andere Form der Warnung stattfinden.
Fehlerhafte Zustände in PEAR-Packages für PHP 5 müssen über Exceptions gemeldet werden. Nicht mehr verwendet werden sollten Fehlercodes oder ein PEAR_Error-Objekt. Diese Regel gilt natürlich nicht, wenn das Package kompatibel mit PHP 4 bleiben muss. In diesem Fall gelten die Konvention der PEAR Coding Standards unter PHP 4 weiter.
Eine Exception sollte immer geworfen werden, wenn ein fehlerhafter Zustand auftritt, entsprechend der Definition im vorherigen Abschnitt. Die geworfene Exception sollte genügend Informationen enthalten, um den Fehler debuggen zu können und schnell dessen Grund herauszufinden. Bedenken Sie, dass in Produktionsumgebungen keine Exception an den Endanwender durchdringen sollten. Deshalb muss man sich keine Gedanken machen über die Komplexität der Fehlermeldung.
Die Basis-Klasse PEAR_Exception enthält eine wörtliche Beschreibung des Fehlers, womit der Programmzustand beschrieben wird, der zum Fehler führte, und - optional - Execptions, die durch untergeordnete Programmaufrufe herbei geführten wurden und die ursprüngliche Ursache des Fehlers darstellen können.
Die Arten von Informationen die in einer Exception enthalten sein müssen, hängt von der Art des Fehlers ab. Es gibt drei Varianten von Exceptions:
Fehler, die während der Vorabprüfung auftreten können.
Fehler, die durch untergeordneten Bibliotheksaufrufe auftreten und durch Fehlercodes oder -Objekte signalisiert werden
Nicht-korrigierbare Exceptions von untergeordneten Bibliotheken.
Fehler, die während der Vorabprüfung auftreten können, sollten eine Beschreibung der fehlgeschlagenen Prüfung enthalten. Wenn möglich sollte der fehlerhafte Wert mit angegeben werden.
Beispiel 3-4.
|
Fehler, die durch untergeordneten Bibliotheksaufrufe auftreten und durch Fehlercodes oder -Objekte signalisiert werden, sollten in Exceptions umgewandelt werden, wenn diese nicht behoben werden können. Die Fehlerbeschreibung sollte die originale Fehlerinformationen enthalten bzw. entsprechend konvertiert werden. Am Beispiel der obigen connect()-Methode:
Beispiel 3-5.
|
Nicht-korrigierbare Exceptions von untergeordneten Bibliotheken sollten weitergeleitet oder erneut geworfen werden. Wenn sie weitergeleitet werden soll, dann behandeln Sie die Exception nicht weiter. Wenn Sie die Exception erneut werfen, dann müssen Sie die originale Exception in der neuen Exception verpacken.
Beispiel 3-6. Eine Exception neu verpacken
|
Beispiel 3-7. Eine Exception weiterleiten
|
Die Entscheidung, ob eine Exception neu verpackt oder weitergeleitet werden soll, ist eine Frage der Software-Architektur. Exceptions sollten weitergeleitet werden, ausser in zwei Fällen:
Die originale Excpetion ist von einem anderen Package. Wenn diese weitergeleitet wird, dann würden Details der Implementierung nach aussen dringen.
Die Methode kann nützliche Debug-Informationen ergänzen.
Exceptions sollten niemals als Bestandteil des normalen Programmflußes benutzt werden. Wenn alle Logik zur Behandlung von Exceptions entfernt würde (try-catch-Statements), dann sollte der verbliebende Code den "wahren Pfad" repräsentieren -- dem Programmfluß, wenn keinerlei Fehler auftreten würden.
Diese Forderung entspricht der Erwartung, dass Exceptions nur bei fehlerhaften Zuständen geworfen werden sollten und niemals bei regulären Zuständen.
Ein Beispiel für die falsche Benutzung der Exception-Weiterleitung ist die Rückgabe eines Wertes eines rekursiven Aufrufs:
Beispiel 3-8.
|
Im Beispiel wird die ResultException benutzt, um "schnell" wieder aus der Rekursion heraus zu kommen. Das ist im Fehlerfall tatsächlich praktisch, in diesem Fall, aber nur ein Beispiel für einen faulen Programmierer.
Alle Exceptions, die von Packages geworfen werden, müssen von PEAR_Exception abstammen. PEAR_Exception bietet zusätzliche Fähigkeiten, um andere Exceptions zu verpacken. Sie finden diese nicht in der obersten PHP Exception-Klasse, sind aber notwendig, um die oben gestellten Anforderungen zu erfüllen.
Zusätzlich sollte jedes PEAR-Package seine eigene Exception-Klasse definieren; der Name der Klasse entspricht dem Muster: <Package_Name>_Exception. Jede Exception sollte von dieser Klasse abgeleitet werden.
Da PHP, im Gegensatz zu Java, es nicht erfordert, mögliche Exceptions in der Funktionssignatur aufzunehmen, ist deren sorgfältige Dokumentation im Methodenkopf wichtig.
Beispiel 3-9. Exceptions werden dokumentiert mit dem @throws-Schlüsselwort
|
In vielen Fällen wandelt die mittlere Schicht einer Anwendung Exceptions von untergeordneten Methoden in aussagekräftiger, anwendungsspezifische Exceptions. Das sollte ebenfalls angesprochen werden:
Beispiel 3-10.
|
In anderen Fällen kann ihre Methode als Filter fungieren, der nur bestimmte Exceptions weiterleitet. Dann sollten Sie dokumentieren, welche Exceptions nicht von Ihrer Methode abgefangen werden.
Beispiel 3-11.
|
Exceptions spielen eine kritische Rolle in der API ihrer Bibliothek. Entwickler, die Ihre Bibliothek verwenden, sind abhängig von der angemessenen Beschreibung wo und warum Exceptions auftreten in Ihrem Package. Auch die sorgfältige Planung der Fehlermeldungen ist ein wichtiger Faktor für die Erhaltung der Rückwärts-Kompatibilität.
Da Exceptions ein integraler Bestandteil der API ihres Packages sind, darf bei Änderungen daran die Rückwärts-Kompatibilität (BC) nicht grundlos gebrochen werden.
Dinge, die zum Bruch führen:
Jede Änderung an Methoden, die Exceptions werfen.
Wenn eine Exception-Klasse verwendet wird, die höher in der Vererbungskette liegt, als die ursprüngliche. Zum Beispiel, wenn Sie in einer neueren Version eine PEAR_Exception werfen würden, in der alten aber z.B. PEAR_IOException verwendet haben.
Dinge, die nicht zum Bruch führen:
Wenn eine abgeleitete Klasse der originalen Exception verwendet wird. Zum Beispiel, wenn Sie in der aktuellen Version eine PEAR_IOException werfen, und in älteren Versionen PEAR_Exception. Natürlich nur unter der Voraussetzung, dass PEAR_IOException von PEAR_Exception) abgeleitet ist.
| E_STRICT-kompatibler Code (Previous) | (Next) Best practices | ||||||||
| |
|||||||||
|
|||||||||