Olaf Schneider: Exceptions versus anderes Errorhandling

Hallo php5-ler,

Nun gibt es php5 schon etwas länger im produktiven Einsatz. Deshalb möchte ich die vor einem knappen Jahr in Exceptions in PHP5 schon einmal angerissene Diskussion neu aufleben lassen:

Welche Fehler sollte man per Exception behandeln, welche mit anderen Methoden, z. B. Rückgabe eines Fehlerobjekts.

Intuitiv würde ich sagen, dass unerwartete und fatale Fehler durch Exceptions behandeln werden sollten:

  • Datenbankverbindung fehlgeschlagen
  • Klassendatei nicht gefunden
    ...

Was ist aber mit Fehlern, die behandelt werden _müssen_, aber vorkommen _dürfen_:

  • Keine xml-Datei zu dieser URL gefunden
  • xml in Datei xyz nicht wohlgeformt
    ...

Einen Schritt weiter: Falls ich Exceptions benutze, empfiehlt es sich eher, mit Errorcodes zu arbeiten oder sollte für jede Ausnahme eine eigene Klasse von Exception abgeleitet werden?

Mir ist klar, dass es hier kein richtig oder falsch gibt und auch die üblichen Arbeitsmethoden von Sprache zu Sprache differieren. Dennoch möchte ich gerne von Euch wissen, wie _Ihr_ darüber denkt und welchen Nachteil ein eher aufwändiges Exceptionhandling haben könnte.

Österliche Grüße
Olaf Schneider

  1. Hello,

    Intuitiv würde ich sagen, dass unerwartete und fatale Fehler durch Exceptions behandeln werden sollten:

    Das sehe ich genauso. Ausnahme-Fehler mit Exceptions behandeln, Statusmeldungen (also vorhergesehene "Fehler") mit Rückgabewerten

    Spannend wird es doch eigentlich erst, wenn man Prozesse abspaltet, die dann "alleine" im Hintergrund weiterwerkeln.

    Harzliche Grüße vom Berg
    http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau

  2. Moin!

    Hallo php5-ler,

    Ich benutze noch PHP4, verstehe aber auch so genug von Ausnahmen (Dank C++).

    Welche Fehler sollte man per Exception behandeln, welche mit anderen Methoden, z. B. Rückgabe eines Fehlerobjekts.

    Was ist denn nach deiner Definition der Unterschied zwischen dem Werfen einer Ausnahme und der Rückgabe eines Fehlerobjektes? In beiden Fällen wird die Ausführung des aktuellen Unterprogrammes abgebrochen und der Aufrufer hält ein Objekt in seinen Händen, welches ihm (wünschenswerter Weise) verrät, weshalb er wieder zurück ist.

    Intuitiv würde ich sagen, dass unerwartete und fatale Fehler durch Exceptions behandeln werden sollten:

    • Datenbankverbindung fehlgeschlagen
    • Klassendatei nicht gefunden
      ...

    Es gibt sogar Ansätze, Ausnahmen zum Unterbrechen von quasi-Endlosschleifen zu benutzen. Ich denke allerdings, dass Ausnahmen, auch von der Bezeichnung dieses Konstrukts her, für Fehlerfälle benutzt werden sollten. In C++ beispielsweise verwende ich Ausnahmen für alle möglichen Fehler, bei denen man in C häufig NULL zurückgäbe. Der Vorteil an Ausnahmen ist allerdings, dass man zusätzlich zum Rücksprung zum Aufrufer noch Informationen über den Grund des Rücksprungs mitgeben kann.

    Was ist aber mit Fehlern, die behandelt werden _müssen_, aber vorkommen _dürfen_:

    • Keine xml-Datei zu dieser URL gefunden
    • xml in Datei xyz nicht wohlgeformt
      ...

    Du sagst es doch selbst: Solche Fehlerfälle dürfen vorkommen, müssen aber behandelt werden. Bei der Verwendung von Ausnahmen muss automatisch sichergestellt sein, dass diese behandelt werden, weil sonst die Ausführung des Programms abgebrochen wird. Allerdings halte ich in solchen Fällen, sofern der Abbruchgrund dem Aufrufer bekannt ist, die Rückgabe eines entsprechenden NULL-Wertes z.B. für vollkommen legitim.

    Einen Schritt weiter: Falls ich Exceptions benutze, empfiehlt es sich eher, mit Errorcodes zu arbeiten oder sollte für jede Ausnahme eine eigene Klasse von Exception abgeleitet werden?

    Ich bevorzuge das Werfen von Ausnahmeobjekten, d.h. von einer Exception-Klasse abgeleitetenden Objekten, weil dies einiges an Aufwand erspart: Es muss nirgendwo hinterlegt werden, was dieser Fehlercode bedeutet, stattdessen ergibt sich der Kontext aus der abgeleiteten Klasse. Für die Internationalisierung mag es allerdings sinnvoll sein, im Ausnahmeobjekt Codes oder Kurztexte statt kompletter Fehlermeldungen zu speichern.

    […] Dennoch möchte ich gerne von Euch wissen, wie _Ihr_ darüber denkt und welchen Nachteil ein eher aufwändiges Exceptionhandling haben könnte.

    Ich sehe die ausgeprägte Benutzung von Ausnahmen nicht als aufwändig oder nachteilig an, sondern eher unterstützend, gerade beim Ausführen mehrerer kritischer, d.h. potenziell fehlschlagender, Funktionen an, weil man nur eine Fehlerbehandlung benötigt, statt entsprechender Abfragen um jeden kritischen Funktionsaufruf. Außerdem kann die Ausnahme dort behandelt werden, wo es sinnvoll ist, während Rückgabewerte eventuell mehrfach weitergegeben werden müssen, bis eine sinnvolle Stufe zur Behandlung erreicht ist.

    Frohe Ostern,
    Robert

    1. Hallo Robert,

      vielen Dank für Deine ausführliche und interessante Antwort. Ich habe inzwischen entschieden, alle zu behandelnen Fehler über Exceptions abzuwickeln. Dieses schien mir eleganter als eigene Fehlerobjekte, die letztlich auch nichts anderes machen.

      Ich habe eine eigene Exception, die sich von der Exception-Basisklasse ableitet. Weitere modulspezifische Exceptions erweitern wiederum diese eigene Exception. Inwieweit diese pro Fehler noch Unterklassen erhalten oder ob ich mit Fehlercodes arbeite, habe ich noch nicht entschieden. Das kann sich auch während der Implementierung noch ändern.

      Gruß
      Olaf

      1. Moin!

        vielen Dank für Deine ausführliche und interessante Antwort.

        Es freut mich, dass ich dir helfen konnte.

        Ich habe eine eigene Exception, die sich von der Exception-Basisklasse ableitet. Weitere modulspezifische Exceptions erweitern wiederum diese eigene Exception. Inwieweit diese pro Fehler noch Unterklassen erhalten oder ob ich mit Fehlercodes arbeite, habe ich noch nicht entschieden. Das kann sich auch während der Implementierung noch ändern.

        Ich habe damals für meine Programmierung mit C++ auch einen universelle Ausnahmeklasse namens »Towel« geschrieben, die flexibler als die Klassen der Standardbibliothek zu handhaben ist. Der Name „Towel“ ist ein kleines Wortspiel: Das Werfen einer Ausnahme, throw Towel, heißt auf Deutsch soviel wie „werfe das Handtuch“.

        Was ich bereits meinte: Ich finde eine Anweisung (C++-Beispiel) wie

        throw FileError(file_name, errno)

        aussagekräftiger als

        throw std::runtime_error(file_name + ": " + std::strerror(errno)

        weil ich im ersten Fall, dass es Probleme mit einer Datei gab, im zweiten Fall weiß ich nur, dass ein Laufzeitfehler aufgetreten ist. Dass std::runtime_error vielleicht die Basisklasse von FileError, braucht erst einmal keine Rolle zu spielen.

        Viele Grüße,
        Robert