Výnimky sú nástrojom objektovo orientovaného programovania, ktoré poskytuje elegantný spôsob vyhadzovania a spracovania (ošetrenia) chýb aplikácie.
Výnimka je najprv vyhodená (thrown
), spracovaná (try
) a zachytená (catch
). Povinné je len hádzanie.
Pred vznikom výnimiek bolo ošetrovanie chýb v programovaní veľmi komplikované, pretože sme sa museli spoliehať na návratové hodnoty funkcií, zachytávať ich vlastným spôsobom a podľa toho sa správať.
Samotné funkcie v skutočnosti nevynucujú spracovanie chýb, čo môže viesť k fatálnym problémom, ale David o tom písal v Programátori neignorujú chyby.
Príklad zabudnutého spracovania chýb:
// presun z disku na diskcopy('c:/oldfile', 'd:/newfile');unlink('c:/oldfile');// ak prvá operácia zlyhá, súbor sa nenávratne vymaže
Je to preto, že správny spôsob spracovania výstupu z funkcie copy()
je nepokračovať a vyhodiť chybu. V prípade starých dobrých funkcií to môže vyzerať takto:
function backup(): bool{if (copy('c:/oldfile', 'd:/newfile')) {return unlink('c:/oldfile');}return false;}
Naša funkcia backup()
vráti true
len vtedy, ak funkcia copy()
nezlyhala a funkcia unlink()
vrátila true
. V opačnom prípade vráti hodnotu false
.
Je to však teraz pre aplikáciu bezpečné? Nie je! Pretože teraz musíme spracovať výstup funkcie backup()
v mieste, kde ju voláme, a ak zlyhá, nebudeme ani vedieť prečo. Skrátka, vráti false
a my musíme chybu nejako zistiť sami. Myslím, že v tomto prípade je dobré vidieť, že programátori často rezignujú na ošetrovanie chýb alebo jednoducho zabudnú niečo ošetriť a aplikácia kvôli tomu vyhodí ťažko zistiteľné chyby.
Riešením tohto problému je použitie výnimiek, ktoré si vynútia ošetrenie, a ak nie sú ošetrené, aplikácia úplne spadne a vždy zistíme prečo.
V PHP je výnimka špeciálny druh rozhrania implementovaný natívnou triedou Exception
, ktorú budeme používať.
Ak spracovanie niektorej časti programu zlyhá, jednoducho vyhodíme výnimku popisujúcu problém:
if (copy('c:/oldfile', 'd:/newfile') === false) {throw new \Exception('Nemožno skopírovať súbor "oldfile".');}
Vyhodenie výnimky sa vykoná pomocou kľúčového slova throw
, po ktorom nasleduje vytvorenie inštancie triedy s výnimkou. Inštanciu môžeme získať aj iným spôsobom (napríklad odovzdaním z premennej) a samotné vytvorenie inštancie výnimky nespôsobí jej vyhodenie.
Prvý argument konštruktora triedy \Exception
prijíma text výnimky, ktorý by mal stručne vysvetliť, čo sa práve stalo. Vhodným postupom je uviesť aj informácie o vykonávanej operácii a odkaz na údaje. Ak napríklad zlyhalo kopírovanie súboru, je vhodné odovzdať názov súboru. Ak sa vykonanie dotazu SQL nepodarí, opäť odovzdáme vykonávaný dotaz. To nám neskôr veľmi pomôže pri riešení chýb, pretože presne vidíme, v čom je problém.
Majme napríklad funkciu backup()
, ktorá zálohuje dáta a môže vyhodiť pár chýb:
function backup(): void{if (copy('c:/oldfile', 'd:/newfile')) {if (unlink('c:/oldfile') === false) {throw new \Exception("Nemožno odstrániť starý súbor.);}}throw new \Exception("Nemožno kopírovať záložné súbory.);}
Všimnite si, že funkcia nevracia žiadny výstup a v definícii sme uviedli typ void
. Funkcia nemusí nič vracať, pretože za úspech sa považuje stav, keď nie je vyhodená žiadna chyba, a nepotrebujeme ošetrovať pozitívny scenár.
Ak by sme funkciu použili v aplikácii bez ošetrenia, napríklad takto:
echo "Zálohovanie súborov...;backup();echo "Zálohovanie dokončené.;
Takto to funguje bežne. Ak však dôjde k chybe, skript sa automaticky ukončí a na výstupe sa zobrazí text výnimky. Dôležité je, že nebude pokračovať vo vykonávaní kódu a vieme, že nedôjde k poškodeniu údajov.
Ak chceme pokračovať vo vykonávaní, musíme chybu odstrániť, čo urobíme pomocou konštrukcií try
a catch
:
echo "Zálohovanie súborov...;try {backup();} catch (\Exception $e) {echo 'Zálohovanie zlyhalo: ' . $e->getMessage();}echo "Zálohovanie dokončené.;
Ak je vyhodená výnimka, zavolá sa kód v oblasti catch()
(ktorý akceptuje výnimku, ak zodpovedá jej dátovému typu) a vykoná sa vnútorný kód.
Vždy získame inštanciu triedy výnimiek, ktorú môžeme použiť napríklad na zobrazenie chybovej správy, ktorá sa spracúva metódou getMessage()
. Užitočné je tiež poznať metódu getFile()
, ktorá vracia diskovú cestu k súboru obsahujúcemu chybu, getCode()
, ktorá vracia stavový kód chyby, a getLine()
, ktorá vracia číslo riadku, na ktorom bola vyhodená výnimka.
Okrem základnej výnimky \Exception
obsahuje PHP aj ďalšie preddefinované typy výnimiek, ktoré sú vhodné pre rôzne prípady použitia.
Typ údajov | Vysvetlenie |
---|---|
LogicException |
Logická chyba, predvídateľná pri návrhu programu |
BadFunctionCallException |
Chyba volania funkcie; funkcia nebola nájdená; volanie nie je povolené |
BadMethodCallException |
Chyba volania metódy |
InvalidArgumentException |
Zlý (neplatný) argument odovzdaný funkcii alebo metóde |
OutOfRangeException |
Hodnota mimo rozsahu poľa alebo kolekcie |
LengthException |
Hodnota prekračuje povolenú dĺžku |
DomainException |
Hodnota nepatrí do požadovanej domény alebo rozsahu |
RuntimeException |
Chyba zistiteľná len za behu (napríklad neúspešný zápis do súboru) |
OverflowException |
Preplnenie vyrovnávacej pamäte alebo aritmetickej operácie, často spôsobené spracovaním väčšieho množstva údajov, ako sa očakávalo |
UnderflowException |
Podpĺňanie vyrovnávacej pamäte alebo aritmetická operácia, bolo odovzdaných menej údajov, ako sa očakávalo |
OutOfBoundsException |
Index mimo rozsahu poľa alebo kolekcie |
RangeException |
Hodnota nie je v požadovanom rozsahu |
UnexpectedValueException |
Neočakávaná hodnota (napr. návratová hodnota funkcie) |
Výnimkám LogicException
a RuntimeException
by sa malo zabrániť správnym návrhom programu. Osobne ich používam len vo výnimočných situáciách, napríklad pri neúspešnom zápise do súboru a pri komunikácii s externou službou.
Odporúčam vôbec nezachytávať RuntimeException
a nechať aplikáciu zlyhať. Zvyčajne ide o závažný problém, ktorý by ste mali čo najskôr nahlásiť.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | sk