Kromě základní třídy Exception disponuje PHP počínaje verzí 5.1.0 celou škálou dalších předpřipravených výjimek. Než si tedy vytvoříte novou třídu, zkuste se podívat, jestli by vám nevyhovovala některá z těchto:

  • LogicException – předvídatelné již při návrhu programu
    • BadFunctionCallException – chyba při volání funkce; funkce nenalezena; volání nepovoleno
    • BadMethodCallException – totéž pro metody
    • InvalidArgumentException – špatný argument předaný funkci
    • OutOfRangeException – index mimo rozsah pole či kolekce
    • LengthException – hodnota překračuje povolenou délku
    • DomainException – hodnota nespadá do požadované domény, rozsahu
  • RuntimeException – zjistitelné pouze za běhu programu
    • OverflowException – přetečení bufferu či aritmetické operace; více dat než očekáváno
    • UnderflowException – podtečení bufferu či aritmetické operace; méně dat než očekáváno
    • OutOfBoundsException – index mimo rozsah pole či kolekce
    • RangeException – hodnota nespadá do požadovaného rozsahu
    • UnexpectedValueException – neočekávaná hodnota (např. návratová hodnota funkce)

Tyto výjimky nemají žádnou funkčnost navíc, jen tvoří předpřipravený strom identifikátorů. Sice jejich použití doporučuji, ale vadí mi „akademický“ duch, tj. že nejsou zvoleny prakticky. Rozdíl mezi OutOfBoundsException, OutOfRangeException a RangeException mi připadá mlhavý, zatímco nějaká ***NotFoundException docela chybí.

Jak chápat LogicException vs. RuntimeException?

LogicException představuje výjimečný stav, kterému můžeme předejít správným návrhem programu. Například InvalidArgumentException vyhodí funkce, která jako argument očekávala pole a dostala řetězec. Jde o signál pro programátora, že má v kódu chybu a proto je lepší je nechat probublat až nahoru a zalogovat. Takže k nim připojujte co nejvýstižnější zprávu, naopak specifická třída není podstatná.

Naproti tomu RuntimeException reprezentuje chybu zjistitelnou pouze za běhu programu. Příkladem může být otevření souboru, které skončí chybou ‚soubor nenalezen‘. I kdybychom existenci souboru ověřili, tak v mezičase před otevřením by mohl být smazán (viz atomické operace se soubory). Běhové výjimky mohou být opět adresovány člověku (neřešit, probublat, zalogovat), nebo naopak aplikaci samotné. V tom případě jejich zachycení představuje jakési „IF“, za kterým následuje kód řešící situaci. Pak používejte a odvozujte specifické třídy, naopak zpráva není klíčová.

Zend Framework – tak tudy ne, přátelé

Správně navrhnout hierarchii výjimek není legrace a příkladem slepé a možná i hluché uličky je třeba Zend Framework. Některé konvence tohoto jinak zdatného frameworku jsou nešťastné a hierarchie výjimek, která otrocky kopíruje strukturu tříd, je jednou z nich. Každá třída vyhazuje pouze výjimky s názvem {NAZEV_TRIDY}_Exception, ať už je důvod chyby jakýkoliv. Přitom třídu, která výjimku vyhodila, mohu zjistit z backtrace, zatímco pro zpracování nebo kaskádovité zachytávání mi její znalost příliš nepomůže.

Kupříkladu knihovna Zend_Mail vyhazuje při

  • volání dosud neimplementované metody,
  • užití nesprávného argumentu,
  • chybě při mazání e-mailu

výjimku Zend_Mail_Storage_Exception, jen s různým textem zprávy. Užitečnější by bylo vyhodit BadMethodCallException, InvalidArgumentException a teprve ve třetím případě vlastní Zend_Mail_Storage_Exception.