Objekty v PHP 5 - 7. díl

V dnešním pokračování seriálu o PHP 5 se zaměříme na výjimky, tedy moderní způsob ošetření chybových stavů.

Úvod

PHP verze 5 podporuje výjimky. Výjimky jsou moderní způsob ošetření chybových stavů. Výjimka může být definována jako událost, která nastane během provádění PHP skriptu a která naruší normální běh provádění instrukcí PHP skriptu. Výjimka může být vyvolána při jakékoli události, kterou určíme. Mechanismus výjimek umožňuje tyto chyby zachytit a ošetřit námi určeným způsobem.

Pro práci s výjimkami slouží tři klíčová slova. Jsou to slova throw, try a catch. Pomocí těchto nových klíčových slov funguje celý mechanismus výjimek. Protože výjimka je speciální událost, která nastává v PHP skriptu, je třeba mít možnost výjimku vyrobit. Tato výroba výjimky je možná pomocí klíčového slova throw, které způsobí „vyhození“ výjimky. Nejjednodušší kód, který pro demonstraci výjimek mohu napsat je zhruba následující:

<?php
throw new Exception;
?>

Výše uvedeným kódem nedělám nic jiného, než že „vyhazuji“ výjimku, tedy způsobuji speciální událost, která se potom ošetřuje mechanismem výjimek. Za klíčovým slovem throw, které vlastně způsobuje vyhození výjimky potom píšu proměnnou, což je instance třídy, který bude obsahovat informace o výjimce. V našem případě použiji speciální třídu Exception. Mohl bych použít také libovolného potomka třídy Exception.

Třída Exception

Třída Exception je základní, do PHP vestavěná třída, která obsahuje nejdůležitější informace o výjimce. Obsahuje jméno souboru, ve kterém nastala výjimka, dále číslo řádky v souboru, ve kterém nastala výjimka, dále čísly chyby a nějakou chybovou zprávu. Každé vyhození výjimky pomocí klíčového slova throw musí obsahovat proměnnou, která obsahuje třídu Exception, nebo libovolného jejího potomka. Samotná třída Exception je již automaticky definována v PHP a není třeba jí nijak definovat. Její naznačená definice by vypadala nějak takto:

<?php
class Exception
{
   protected $message = `Unknown exception`;
   protected $code = 0;
   protected $file;
   protected $line;
 
   function __construct($zprava = null, $kod_chyby = 0);
 
   final function getMessage(); 
   final function getCode();
   final function getFile();
   final function getLine();
   final function getTrace();
   final function getTraceAsString();
 
   function __toString();
}
?>

Základními parametry výjimky je tedy chybová zpráva a chybový kód, což jsou i parametry konstruktoru třídy Exception. Pokud bych tedy pozměnil svůj první příklad, mohu jej zapsat třeba nějak takto:

<?php
throw new Exception(`zpráva`,3);
?>

Výše uvedeným způsobem bych vyhodil výjimku, která by nesla jako svojí chybovou zprávu řetězec „zpráva“ a jako svůj chybový kód číslo 3. Pokud bych vyzkoušel výše uvedený příklad spustit, pak mě PHP uvítá následující zprávou:

Fatal error: Uncaught exception `Exception` with message `zpráva` in C:\php5\a.php:2
Stack trace:
#0 C:\php5\a.php(2): unknown()
#1 {main}
  thrown in C:\php5\a.php on line 2

V této zprávě mi sděluje, že byla vyhozena výjimka, kterou nikdo nezachytil (jak se zachycují výjimky si ukážeme za chvíli), a že byla vyhozena v souboru C:\php5\a.php na řádce číslo 2. Je tam také vypsáno, že výjimka nesla chybovou zprávu „zpráva“ a celé je to zakončeno výpisem zásobníku PHP.

Chytání výjimek

Zatímco do této chvíle jsem se zabýval v zásadě tím, jak výjimku vyvolat, tedy „vyhodit“, budu se v této části zabývat tím, jak lze výjimku zachytit a ošetřit. Celé schéma výjimek se dá v podstatě zjednodušeně popsat tak, že na místě, kde nastane chyba vyhodím výjimku, a na místě, kde chci chybu ošetřit provedu ošetření této výjimky.

Velkou výhodou výjimek je obrovské zpřehlednění kódu. Dále je možné chybu ošetřit na nejvhodnějším možném místě, a to může být i naprosto jinde, než je místo vzniku chyby. Můžu dokonce různé druhy chyb ošetřovat na různých místech kódu ve skriptu.

Pro ošetřování výjimek slouží dvě klíčová slova, a to try a catch. Pomocí klíčového slova try vymezím blok kódu v PHP skriptu, ve kterém chci ošetřovat výjimky. Pomocí slova catch se pak jednotlivé výjimky chytají, pokud nastanou. Nejlépe je to vidět na jednoduchém příkladě:

<?php
try
{
  throw new Exception(`moje výjimka`,0);
}
catch (Exception $vyjimka)
{
  echo `Zachycena výjimka`;
}
?>

Jak je vidět v příkladě uvedeném výše, ohraničil jsem pomocí slova try blok kódu, ve kterém chci zachytit výjimky. V mém jednoduchém příkladě obsahuje blok try pouze jeden řádek kódu, ale to není podstatné. Bezprostředně za blokem try, přesněji za jeho uzavírací závorkou } musí následovat blok catch, který má v závorce uvedeno, jaký typ výjimky je schopen zachytit. V našem případě je schopen zachytit výjimku představované třídou Exception a nebo jejím potomkem, jinak řečeno je schopen zachytit naprosto všechny výjimky. Příkazy, které jsou uvedeny v bloku catch se provedou jenom tehdy, pokud je zachycena výjimka.

Celé schéma zachycování výjimek funguje tak, že se normálně provádí náš PHP skript. Pokud nastane chyba, můžeme tuto chybu ohlásit vyhozením výjimky. Jakmile je vyhozena výjimka, dostane se PHP skript do speciálního stavu. V tomto stavu už neprovádí náš PHP skript, ale hledá se blok catch, který je schopen zachytit vyhozenou výjimku. Pokud se takový blok catch najde, předá se mu vyhozená výjimka ke zpracování. Pokud se nenajde, je PHP skript předčasně ukončen s chybovou zprávou.

Všechny dosud uvedené příklady byly umělé a v praxi je asi nikdy nepoužijete. Proto uvedu trochu realističtější příklad, jak by mohlo vypadat třeba ošetřování proti dělení nulou. Předem napíšu, že se jedná o složitější kód:

<?php
class deleni_nulou extends Exception
{
  function __construct()
  {
    parent::__construct(`Dělení nulou.`,0);
  }
}
 
$a = 3;
$b = 0;
 
try
{
  if ($b == 0)
    throw new deleni_nulou;
  $c = $a/$b;
  echo `Výsledek je `,$c;
}
catch (deleni_nulou $vyjimka)
{
  echo `Nastalo dělení nulou.`;
}
catch (Exception $vyjimka)
{
  echo `Nastala chyba `, $vyjimka->getMessage();
}
?>

Ve výše uvedeném příkladě je vytvořena třída deleni_nulou, která bude sloužit k tomu, aby byla vyhazována při výjimkách, kdy má nastat dělení nulou. Námi vytvořená třída musí být potomek třídy Exception, abychom mohli třídu používat pro vyhazování výjimky.

V bloku try nejdříve otestujeme jestli se má dělit nulou, a pokud ano, vyhodíme výjimku. Pokud ne, pak dělení může bez problémů proběhnout, nic nám tedy nebrání, abychom vypsali výsledek.

V našem příkladě je také vidět, že za blokem try může následovat více bloků catch. V našem příkladě máme dva bloky catch. Pak se při výjimce hledá první blok catch, který vyhovuje výjimce. Pokud nastane výjimka vyhozená s třídou deleni_nulou, použije se první blok catch a vypíše se, že nastalo dělení nulou. Pokud by nastala jiná výjimka, použije se druhý blok catch, který zachytává všechny výjimky odvozené od třídy Exception, tedy naprosto všechny výjimky.

Výhody a nevýhody výjimek

Výhodou výjimek je to, že hlavně ve větším projektu dokáží velmi zpřehlednit kód. Chyby můžeme ošetřovat i bez výjimek, ale pak o hodně přicházíme. S pomocí výjimek se velmi blížíme ideálu, kdy píšeme kód skoro tak, jako by neměla nastat žádná chyba. Tedy tak, jako kdyby všechno vždycky dopadlo výborně. Pokud čistě náhodou chyba nastane, pouze vyhodíme výjimku a píšeme kód dál, jako kdyby nikdy žádná chyba nebyla. Všechny chyby pak coby výjimky ošetřujeme na jiných místech, speciálně k tomu určených. Je tedy možné napsat čistý kód a zvlášť napsat ošetření chyb.

Zejména ve větších projektech dokáže ošetřování chyb pomocí výjimek dělat skoro zázraky. Na druhé straně je potřeba zmínit, že samotné PHP k používání výjimek nijak nenapomáhá. Všechny funkce, které PHP obsahuje hlásí chybu pomocí návratové hodnoty funkce a nikdy ne pomocí výjimky. Z tohoto pohledu se zdá, jako kdyby výjimky do PHP skoro ani nepatřily a byly tam něco navíc. Proto všechna práce spojená s vyhazováním výjimek bude ležet na bedrech programátora a samotné PHP mu nijak nepomůže.

Diskuze (15) Další článek: Active 24 kupuje Internet Club a CP Online

Témata článku: Software, Programování, PHP, Echo, Blok, Díl, Libovolné místo, Klíčový parametr, Celý mechanismus, Catch, Objekt, Libovolný kód, Uvedený způsob, Chyba, Zachycování, První blok


Určitě si přečtěte

Apple dal do MacBooku procesor Core i9 a 4TB SSD. Ani se neptejte, co za to chce...

Apple dal do MacBooku procesor Core i9 a 4TB SSD. Ani se neptejte, co za to chce...

** Apple aktualizoval notebooky MacBook Pro, dostaly nový hardware ** Těšit se můžete na nové procesory a větší paměť ** Cena nejvybavenějšího modelu překročí 200 tisíc korun

Martin Miksa | 99

Alan Turing: Genius, který matematicky stvořil počítač

Alan Turing: Genius, který matematicky stvořil počítač

Řešením matematického problému se dostal k modelu teoretického stroje, který nese jeho jméno a je základem logiky univerzálních počítačů.

Pavel Tronner | 56

Šmírovačka kamerami Googlu: Koukněte se, co nového zachytily na Street View

Šmírovačka kamerami Googlu: Koukněte se, co nového zachytily na Street View

Google stále fotí celý svět do své služby Street View. A novodobou zábavou je hledat v mapách Googlu vtipné záběry. Podívejte se na výběr nejlepších!

redakce | 44

Budoucnost elektroniky: čeští vědci stojí za revolučním čipem, který nemá ve světě obdoby

Budoucnost elektroniky: čeští vědci stojí za revolučním čipem, který nemá ve světě obdoby

** Čeští vědci pod vedením Tomáše Jungwirtha vyvíjí nový typ revolučního paměťového čipu ** Zatímco v současnosti elektronika pracuje s elektrony, v budoucnu to budou spiny elektronů ** Čipy budou moci být klidně i 1 000x rychlejší a úspornější

Karel Javůrek | 32


Aktuální číslo časopisu Computer

Velký test 18 bezdrátových sluchátek

Vše o přechodu na DVB-T2

Procesory AMD opět porážejí Intel

7 NVMe M.2 SSD v přímém souboji