OOP v PHP: Výjimky v OOP
PHP 5, narozdíl od předešlých verzí, umožňuje využívání výjimek stejně jako ostatní programovací jazyky. Výjimky rozšiřují možnosti ošetřování vzniklých chyb v PHP.
Výjimky jsou objekty. Pro jednodušší práci je v PHP zabudovaná třída Exception, která je navržena speciálně pro výjimky. Výjimka může být hozena (thrown), ošetřena (try) a chycena (catch). Blok try (to, čím výjimku vyhazujete) musí obsahovat alespoň jeden blok catch (to, čím výjimku zachycujete).
Jak to všechno probíhá?
Nejprve je výjimka vyhozena, objekt Exception je zachycen a provádění kódu se zastaví. Cokoli následuje dále, se neprovede. Poté se začne provádět blok, který výjimky zachytává (catch). Pokud není v daném bloku žádný kód pro zpracování výjimky, hledá se blok catch v bloku kódu volajícího. To se opakuje tak dlouho, dokud není nalezen kód pro zpracování výjimky nebo dokud není dosažen vrchol v hierarchii volání. Výjimka může být vyhozena i uvnitř catch bloku. Nezachycená výjimka je fatální chyba!
Ukázka:
<?php try { $zprava = 'Inteligentní zpráva'; throw new Exception($zprava); // Tohle už se nevykoná echo 'Ja jsem zpráva, kterou nikdo nepřečte'; } catch (Exception $e) { echo 'Výjimka zachycena: '. $e->getMessage(); } ?>
Třída exception
PHP má už přednadstavenou třídu Exception, která má definované své přednadstavené metody a vlastnosti. Zjednodušeně vypadá asi takto:
<?php class Exception{ protected $message = 'Unknown exception'; // zpráva výjimky protected $code = 0; // kód výjimky protected $file; // soubor, kde byla výjimka zachycena protected $line; // řádek, kde byla výjimka zachycena function __construct($message = null, $code = 0); final function getMessage(); // zpráva výjimky final function getCode(); // kód výjimky final function getFile(); // soubor final function getLine(); // řádek function __toString(); // formátování řetězce pro výstup } ?>
Hierarchie výjimek
Jak už bylo napsáno dříve, můžeme samozřejmě používat více bloků catch na jeden try. S náročnějšími skripty se zvyšuje i počet možných vyhozených výjimek a tím i riziko, že některou nezachytíme. Proto je dobré používat nějakou hierarchii výjimek.
<?php class zdedenaVyjimka extends Exception {} class dalsiZdedenaVyjimka extends zdedenaVyjimka {} class jesteJedna extends dalsiZdedenaVyjimka {} function faktorial($n){ if($n < 0){ throw new zdedenaVyjimka; }else if($n == 0 || $n == 1){ return $n; }else if($n > 170){ throw new jesteJedna; }else{ return $n * faktorial($n - 1); } } try { $n = 5; $faktorial = faktorial($n); echo "$n = $faktorial"; } catch(dalsiZdedenaVyjimka $e){ echo "Příliš velká hodnota"; } catch(zdedenaVyjimka $e){ echo "Špatná hodnota"; } catch (Exception $e){ echo "Vyskytla se jiná chyba"; } ?>
Nejprve jsou definovány tři třídy (budou fungovat jako výjimky). Jedná se o dědičný strom, druhá dělí vlastnosti první, třetí vlastnosti druhé a tak dále.
Pokud bude proměnná $n menší než nula, pak bude vyhozena zdedenaVyjimka, která bude zachycena druhým blokem catch a vypíše se hodnota „Špatná hodnota“. Pokud bude proměnná $n větší než nula, pak bude vyhozena výjimka jesteJedna. Neexistuje však žádný blok catch, který by ji dokázal zachytit, skript tedy začne hledat rodiče této výjimky. Tím je dalsiZdedenaVyjimka a pro tuto výjimku už blok catch existuje, vypíše se hodnota „Příliš velká hodnota“. Nakonec je definován blok catch pro výjimku Exception. Ten se vykoná pouze tehdy, byla-li vyhozena výjimka, pro kterou neexistuje žádný block catch (tato výjimka však musí být vzdáleným potomkem Exception).
Jednoduše řečeno, pokud PHP nenajde catch blok pro nějakou výjimku, půjde tak dlouho po dědičném stromě, dokud nedosáhne nějaké výjimky, pro kterou je blok catch definován. Tím v podstatě vylučujeme šanci, že by se vyskytla nějaká chyba, kterou nemůžeme zpracovat. Pokud bude vyhozena nějaká nepředpokládaná výjimka, zpracuje ji poslední blok.
Řazení výjimek do kaskády
V PHP existuje možnost vyhazovat výjimky i uvnitř bloku catch. To se může hodit tehdy, pokud chceme zachycenou výjimku zpracovat a předat dále. Třeba dojde-li k chybě v MySQL, skript vyhodí výjimku, kterou zachytí nějaký blok catch. Nějak výjimku zpracuje a podle jejího typu ji pošle dalšímu bloku catch, který si s daným typem chyby poradí lépe. Například George Schlossnagle uvádí tento kód (MysqlException je potomkem Exception):
class MysqlException { //... static function createError($message=false, $code=false){ if(!$code) { $code = mysql_errno(); } if(!$message) { $message = mysql_error(); } swich($code) { case 1062: return new Mysql_Dup_On_Index($message, $code); break; default: return new Mysql_Extension($message, $code); break; } }
Pak voláte pouze MysqlException::createError();…
Velmi elegantně můžete zpracovávat chyby v konstruktoru. Například takto:
<?php class ToBudeChyba{ public function __construct(){ throw new Exception; } public function __destruct(){ echo "Konec"; } } try{ $i = new ToBudeChyba; } catch(Exception $e) {} ?>
Destruktor se nevykoná, uvnitř konstruktoru byla vyhozena výjimka, objekt reálně neexistuje, dokud neproběhne celý konstruktor.
Funkce pro zpracování výjimek
PHP umožňuje použití několika funkcí, které jsou určeny pro výjimky.
set_exception_handler();
Funkce set_exception_handler() umožňuje nastavit defaultní funkci, která bude volána, pokud výjimka nebude zachycena. Obsahuje pouze jeden parametr, a to právě jméno funkce, která bude volána (tato funkce musí být v kódu uvedena dříve než set_exception_handler()).
<?php function exception_handler($exception) { echo "Zpráva výjimky: " , $exception->getMessage(); } set_exception_handler('exception_handler'); throw new Exception('Nezachycená výjimka'); ?>
Jak jste si všimli, vyhazovat výjimku můžeme i mimo blok try. Za výjimku můžeme vložit nějaké hodnoty, zprávu výjimky a kód.
<?php function exception_handler($exception) { echo "Zpráva výjimky: " , $exception->getMessage(); echo "Kód výjimky: " , $exception->getCode(); } $funkce = set_exception_handler('exception_handler'); throw new Exception('Nějaká zpráva',50); ?>
Pokud funkci set_exception_handler() přiřadíme nějakou proměnnou (v předchozím případě $funkce), má to i jisté výhody. Uživatelsky definované funkce jsou uloženy v zásobníku, takže můžete obnovit starou funkci buď uložením další kopie staré funkce do zásobníku…
set_exception_handler($funkce);
…nebo vyzvednutím ze zásobníku takto:
restore_exception_handler();
Pozn. red.: Zdůrazňujeme, že tento text se týká PHP 5.
Mohlo by vás také zajímat
-
Praktické rady na zabezpečení redakčního systému WordPress
27. února 2023 -
AI na dosah ruky: Jak je to s AI v osobních zařízeních?
22. ledna 2024
Nejnovější
-
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024 -
Výkonný a kompaktní: ASOME Max Studio s výjimečným poměrem cena/výkon
11. listopadu 2024
rePhat
Zář 25, 2014 v 13:52Narazil jsem na malou chybku pod zdrojovým kódem u „Hierarchie výjimek“, kde v druhém odstavci stojí: „Pokud bude proměnná $n větší než nula, pak bude vyhozena výjimka jesteJedna“. Myslím že tam mělo být $n větší než 170.
miro
Pro 7, 2016 v 16:20máte u
nastavené display:block;, tzn každý token v příkladech kódu je na vlastním řádku - musel jsem si to vypnout, ať se ten kód dá rozumně přečíst.