Facebook
Twitter
Google+
Kommentare
10

Leere try catch Blöcke

Mit PHP 5 wurden Exceptions eingeführt. Ein toller Tag für uns OOP Fans. Endlich kann man statt über einen „mixed“ Rückgabewert einen aufgetretenen Fehler bekannt machen, die saubere Methode der Ausnahmen (exception) verwenden. Eine Ausnahme wird an einer Stelle geworfen, weitergereicht und an der Stelle bearbeitet, an der es Sinn macht.

Doch leider sieht man immer wieder leere try catch Blöcke. Wenn es einem egal ist, ob eine Methode aufgerufen wird und korrekt terminiert oder nicht, warum ruft man sie denn dann überhaupt auf. Das macht keinen Sinn. Dinge, die manchmal funktionieren, sind die Hölle in der Programmierung. Und wenn man dann nicht mal mitbekommt, dass ein problem aufgetreten ist, hat man doppelt verloren. Versucht mal einen Fehler zu finden, der durch einen leeren Catch Block abgefangen wurde.

Falls man also an eine solche Stelle kommt, sollte man sich über das Design Gedanken machen. In den meisten Fällen ist hier nämlich ein strukturelles Problem vorhanden, das man anders angehen sollte. Zum Glück hilft einem das Zend Studi an dieser Stelle bereits ein wenig. Hier werden Exception, die nicht in irgendeiner Art und Weise bearbeitet werden angemäkelt. Nettes Feature.

„Sinnvoll“ stelle ich mir das nur im Umgang mit Third Party Code vor. Hier kann man oft nicht verhindern, dass „falsche“ Exceptions geworfen werde. In einem solchen Fall kann man mit leben, nicht zu reagiere, wenn der Code trotzdem das tut, was er soll. Vielleicht kann man hier aber trotzdem die Exceptions loggen, um es sich einfacher zu machen. Zumindest sollte man die Stellen im Code markieren, in denen so etwas passiert.

Ach ja, der Umgang mit Ausnahmen gilt natürlich auch für Javascript.

Über den Autor

Nils Langner

Nils Langner ist der Gründer von "the web hates me" und auch der Hauptautor. Im wahren Leben leitet er das Qualitätsmanagementteam im Gruner+Jahr-Digitalbereich und ist somit für Seiten wie stern.de, eltern.de und gala.de aus Qualitätssicht verantwortlich. Nils schreibt seit den Anfängen von phphatesme, welches er ebenfalls gegründet hat, nicht nur für diverse Blogs, sondern auch für Fachmagazine, wie das PHP Magazin, die t3n, die c't oder die iX. Nebenbei ist er noch ein gern gesehener Sprecher auf Konferenzen. Herr Langner schreibt die Texte über sich gerne in der dritten Form.
Kommentare

10 Comments

  1. Mit fällt immer wieder auf, das Entwickler nicht wissen, dass man Exceptions auch je nach Typ anfangen kann. Kleines Beispiel:

    class TestClass {
    public static function throwException() {
    throw new Exception_Three(‚die‘);
    }
    }

    try {
    TestClass::throwException();
    } catch(Exception_One $e) {
    echo „first“;
    } catch(Exception_Two $e) {
    echo „second“;
    } catch(Exception $e) {
    echo „fallback“;
    }

    Reply
  2. Irgendwie hat der Editor den Code abgeschnitten. So ist’s richtig:

    class Exception_One extends Exception { }
    class Exception_Two extends Exception { }
    class Exception_Three extends Exception { }

    class TestClass {
    public static function throwException() {
    throw new Exception_Three(‚die‘);
    }
    }

    try {
    TestClass::throwException();
    } catch(Exception_One $e) {
    echo „first“;
    } catch(Exception_Two $e) {
    echo „second“;
    } catch(Exception $e) {
    echo „fallback“;
    }

    Reply
  3. Interessant finde ich dass in C++ die Compiler so designed sind, dass eine Exception nur etwas kostet wenn diese auch geworfen wird, d.h. es empfiehlt sich nicht diese für den logischen Ablauf zu integrieren, sondern wo einfach Exception geworfen werden könnte, ist das gute alte „if“ einfach performanter. Müsste man mal unter php benchmarken, erörtern oder kennt jemand schon Details dazu?

    Reply
  4. Zum Thema „logischer Ablauf“: Exception heißt „Ausnahme“. Ein „erwarteter“ Zustand kann aber keine Ausnahme sein.

    Klares negativ Beispiel:

    function isLoggedIn() {
    if (!isset($_SESSION[‚loggedin‘]) {
    thorw new UserNotLoggedinException();
    }
    return true;
    }

    Beispiel das, je nach Projekt-Konventionen, Sinn machen kann, nicht unbedingt das beste, aber ich wollte es hier nicht ausreizen:

    function isLoggedIn() {
    if (!session_started()) {
    throw new SessionNotStartedException();
    }
    return isset($_SESSION[‚loggedin‘]);
    }

    Das die Session nicht gestartet wurde deutet auf fehlende Initialisierung des PRogrammes hin, dass der User nicht eingeloggt ist, kann aber durchaus sein und seine berechtigung haben. In einer höheren Ebene kann es dann eine Ausnahme sein, z.B.

    function saveNewData() {
    if (!isLoggedIn()) {
    throw new WhatTheHeckThisShouldHaveBeenCheckedBeforeException();
    }
    /* …. */
    }

    Zum Tema performance: Nach „jeder“ Operation prüft die Engine das Exception flag, ist es gesetzt wird es relativ teuer – es muss ja der richtige Catch-Block gefunden werden und die Execution Frames zwischendrin aufgeräumt werden. Wird keine Exception geworfen kommt nach dem Ende des try-Blocks ein JMP über die Catch-Blöcke hinweg, was aber einer der günstigsten OpCodes ist die wir haben. Wer aber auf sowas achtet und da rummisst macht was radikal falsch, im Zweifel die falsche Sprache. Auf der Ebene auf PErformance zu optimieren führt zu unwartbarem Code…

    Reply
  5. Ah und C++ und Exceptions sind ne ganz andere Kategorie: Zur Performance kann ich dan icht viel sagen, der vom Compiler generierte Code wird jedenfalls deutlich komplexer sobald man Exceptions in C++ verwendet, zudem muss man extrem aufpassen nicht zu leaken – C++ hat keinen GC-mechanismus, alles was nicht am Stack allokiert ist wird nicht aufgeräumt und man muss entweder aufräumen bevor man die Exception schmeißt oder sich irgendwo die Pointer halten um später aufräumen zu können.

    Reply
  6. Oh nochwas der C++ Fall wird ganz besodners schön, wenn man ein paar Frames dazwischen hat:

    void a(SomeClass *foo) {
    // Darf ich foo hier löschen oder gibt es nen catch Block beim caller der das macht?
    throw 1;
    }

    void b() {
    SomeClass foo = new SomeClass();
    a(foo);
    delete foo;
    }

    void c() {
    try {
    b();
    } catch (int i) {
    // foo aus b() kann ich hier nichtmehr aufräumen -> leak
    }
    }

    Insgesamt bedeutet Exception C++ deutlich mehr Aufwand. So aber gneug der Flamerei dort 🙂
    (achso und ja, C++ hat auch einiges nettes im Angebot .. wobei es an manchen stellen von zu viel Perfektionismus getrieben wurde…)

    Reply
  7. ok, dann nochmal zu php 😉 Kann nur zustimend sagen, dass wohl der Einsatz für ThirdParty Lib’s eine echte echte Berreicherung ist.
    Ein _falscher_ Umgang einer Klasse/Methode durch eine exception klar deutlich wird, da der Intepreter sowieso nicht auf das catchen von möglichen Exceptions besteht, ist es doch eigentlich sinnvoll eine auch leere NullPointerException zu werfen wenn das Argument null ist, aber nicht null sein soll.

    Reply
  8. Nunja, damit gehst Du davon aus, das der Code ausreichend getestet wird – fehlt das passiert beim Anwender etwas das schief geht – weil der, der die Library nutzt nicht davon ausgeht, dass da Exceptions geworfen werden, wobei man da nur sagen kann: Selber schuld 🙂

    Reply
  9. @comment
    „Zum Thema “logischer Ablauf”: Exception heißt “Ausnahme”. Ein “erwarteter” Zustand kann aber keine Ausnahme sein.“

    Logisch betrachtet, ist diese Aussage natürlich einfacher Blödsinn, den auch eine Ausnahme kann erwartet werden (deswegen ja try’n’catch). Aber das wäre unfairerweise auch ein wenig aus dem Zusammenhang gerissen, deswegen hole ich ein wenig aus.

    Eine Exception unterbricht zwar den „erwarteten“ Zustand/Ablauf (wer denkt sich schon was beim proggen?) aber genau deswegen handelt es sich doch um eine Methodik die gerade im Zusammenhang _mit_ dem genannten „logischen Ablauf“ eingesetzt wird.

    So kann man sich nämlich (relativ) einfach sicher sein, das bei einer sauberen Programmierung (und eben intensiver Anwendung von Exceptions) nur dann keine solchen geschmissen werden, wenn alle Parameter im grünen Bereich waren und somit die Logik _nicht_ gefährdet war/ist (!!). Eine Exception die wir selber schmeissen, sichert uns als Autoren doch die Logik unserer Module (für mich einer der wichtigsten Aspekte als Programmierer).

    Gerade bei Einsatz von Fremden Bibliotheken können Exception einmal bei der Integration als auch beim Abfangen von Problemen helfen (wurde in anderen Kommentaren ja schon mehrfach hervorgehoben). Aber gerade auch bei der Arbeit im Team. Lieber mal den Kollegen eine Exception zwischen die Beine werfen als sie ewig nach Bugs suchen lassen (Das ist nicht nur eine Frage von Unit-Tests).

    Dazu Bedarf es auch garnicht soviel Zeilen Code zu, um dauernd neue Exceptions zu Schreiben. Es gibt einige auf Vorrat:

    http://www.php.net/~helly/php/ext/spl/classException.html

    (Übrigens gibts hier einen ganzen Sack voll Logik-Ausnahmen um im Thema zu bleiben)

    Ergo: Ein Programm was keine Exceptions kennt ist ziemlich „weltfremd“, denn im Real Life in the Wild gibts halt immer mal was, was eine begrenzte Programmlogik zerstören kann. Ein Programm läuft eben immer nur im Speicher und dessen Zustand können wir als Programmierer nicht vorhersagen auch wenn wir uns an Syntax und Co klammern. Um mal ganz Grundlegend zu werden: Was macht ein Kernel, wenn er auf unvorgesehens trifft? – _Exception_ Fault.

    Und Danke an Nils, der eben das Ausschalten von Exceptions mit den leeren Catch Blöcken mit dem Beitrag kritisiert. Diese führen nämlich das gesamte Prinzip Ad Adsurdum.

    Quizfrage zum Artikel: Unterbindet der PHP @-Operator das Schmeissen von Exceptions?

    Reply

Leave a Comment.

Link erfolgreich vorgeschlagen.

Vielen Dank, dass du einen Link vorgeschlagen hast. Wir werden ihn sobald wie möglich prüfen. Schließen