© 2013 All rights reserved.
2

Chybová hlášení v PHP

Řekneme si něco o chybových hlášeních jak v PHP, tak v MySQL, nakonec se podíváme vlastní řešení chybových hlášení.

PHP se zpracovává na straně serveru a od toho se taky odvíhí způsob hlášení chyb, které vznikají při parsování kódu.

  • parser errors
  • Fatal Errors
  • Warnings
  • Notices

      Parse Error

      Parse Errors, neboli chyby při čtení jsou většinou chyby syntaktické, které jsou odhaleny ještě před vyhodnocením skriptu. Parser před spuštěním celý skript analizuje a na takovou chybu ve většině případů upozorní.

      Parser nás tím upozorní na skutečnost, že bez opravení chyby nemůže pokračovat a skript nebude vůbec spuštěn. Pak tedy například kód:

      nevrací žádný výsledek, jenom parse error:

      čímž nás informuje o chybě na pátém řádku a celý skript nebude vůbec spuštěn.

      Fatal error

      Fatal errors, neboli závažné chyby jsou většinou chyby sémantické nebo chyby, které vznikají v prostředí:

      Po spuštění tohoto zdrojového kódu dojde k Fatal error chybě, neboť voláme funkci, která neexistuje. Na výstup dostaneme všechno co je správně a je voláno před chybou (toto závisí na verzi PHP), takže v tomto případě:

      Nic z toho co je za chybovým hlášením se neprovede a skript bude zastaven až do opravení chyby.

      Warnig

      Warning, neboli varování o chybě.

      Při varování se provádění skriptu nezastaví, ale parser se pokouší pokračovat v dalším provádění skriptu.

      Varování vznikají v situaci, kdy chyba není natolik závažná, aby ovlivnila provádění celého skriptu. Jedná se většinou o chyby, které jsou ovlivněny prostředím. Takže například pokud nemůže najít daný soubor, který se pokoušíme otevřít nebo k němu nemá přístup, vzniká WARNING.

      Pokud se navíc jedná o příkaz, který ovlivní další funkce, upozorní nás parser o všech těchto funkcích jako chybách. Může se jednat o otevření souboru, nebo o připojení k databázi:

      Tento kód způsobí tři varování (Run-time warnings). Nepodaří se otevřít soubor, to je varování první. Tato chyba ovšem ovlivní i čtení ze souboru, to je druhé varování. A navíc se soubor nemůže podařit zavřít, protože není otevřen a to je varování třetí:

      Notice

      Notice, neboli upozornění se zobrazuje u méně závažných chyb, které parser většinou vyřeší po svém. Tato chybová hlášení jsou většinou vypnuta a nezobrazují se.

      Klasickou ukázkou jsou neinicializované proměnné, se kterými se snažíme udělat nějakou operaci. Tyto proměnné jsou většinou přetypovány na nulovou hodnotu. Proto je tyto chyby těžké odhalit, neboť si je nemusíme všimnout. Skript je totiž vyhodnocen správně, jenom nepracuje tak jak se od něho očekává.

      Pokud není nastaveno vypisování chyb Notice proběhne skript a vypíše 0. pokud je ovšem výpis povolen, vypíše se notice chyba, protože $a je v tomto případě nedefinovaná proměnná:

      V případě notice chyby skript dále pokračuje a je vyhodnocován.

      Error_reporting – úroveň chyb

      V případě že potřebujete, aby se vám některá chybová hlášení vypisovala a jiná ne, můžete použít funkci error_reporting, která dokáže nastavit a ovlivnit způsob výpisu chybových hlášení. Toto je užitečné hlavně při ladění aplikace, kdy je nutné ošetřovat všechny chyby.

      Funkce má jediný parametr a tím je level hodnota výpisu chyb, který se bude vypisovat. Tato hodnota může být číselná nebo zadána jako seznam chybových hlášení, která se mají vypisovat:

      E_ALL

      Bitová maska úroveň chyby popis
      1 E_ERROR závažná chyba
      2 E_WARNING varování před chybou
      4 E_PARSE syntaktická chyba
      8 E_NOTICE upozornění na chybu
      2047 vztahuje se na všechny chyby

      tabulka 1: Hodnoty pro error reporting

      Konstanty a hodnoty uvedené v tabulce můžeme rozšířit ještě o další, které jsou pouze pro PHP4 a v PHP5 se již většinou nevyskytují:

      Bitová maska úroveň chyby popis
      16 E_CORE_ERROR závažné chyby při inicializaci PHP
      32 E_CORE_WARNING varování při inicializaci PHP
      64 E_COMPILE_ERROR závažné chyby při kompilování
      128 E_COMPILE_WARNING varování při kompilování
      256 E_USER_ERROR závažná chyba definovaná uživatelem
      512 E_USER_WARNING varování na způsobenou chybu definovanou uživatelem
      1024 E_USER_NOTICE uživatelem definovaná varování
      2048 E_STRICT upozornění na chybu během spuštění aplikace

      tabulka 2: Další hodnoty pro error reporting

      S PHP4 se v dnešní době setkáváme stále ve velké míře, ale i tak je důležitá spíše první tabulka, kterou určitě využijete častěji.

      Možností jak zapsat úroveň vypisování chyby, kterou chceme zobrazovat, je více. První a nejjednodušší způsob je výpisem úrovně chyby, které uvedeme jako seznam. Při tomto zadávání využíváme tří operátorů:

      • | – nebo
      • ~ – bez této hodnoty
      • & – i tuto hodnotu

      A v praxi potom zapisujeme přímo do zdrojového kódu většinou na začátek souboru takto:

      V takovémto případě uvedeme jako parametr všechny úrovně chybových hlášení, která chceme, nebo nechceme vypisovat včetně příslušných operátorů. Ostatní úrovně, které nejsou uvedeny se zobrazovat nebudou. Defaultní hodnota není nastavena na vypisování úrovně chyb E_NOTICE, pomocí tohoto způsobu jej jednoduše ovlivníte. Tento příklad vám určitě vypíše E_NOTICE chybu.

      Další možností, která je asi nejvyužívanější je číselná hodnota uvedená jako level vypisování úrovně chyb. Tato hodnota se udává jenom jako celé číslo, které je součtem všech bitových masek úrovní, jež chceme vypisovat. Pokud bychom tedy chtěli nastavit zobrazování všech chybových hlášení, nastavili bychom hodnotu na číslo 15 (E_ERROR – 1, E_WARNING – 2, E_PARSE – 4, E_NOTICE – 8 => 1 + 2 + 4 + 8 = 15).

      V tomto případě se nám zase vypíše i NOTICE, neboť jsme natavili vypisování všech chybových hlášení.

      Při číselném vyjádření můžeme zase využívat operátorů, které umístíme mezi číselné hodnoty masek. Pokud bychom chtěli dosáhnout toho, aby se nevypisovali žádná chybová hlášení, nastavíme hodnotu na nulovou:

      Toto je při ladění aplikace ovšem velmi nebezpečné, neboť nebudete informováni o žádné chybě, kterou skript způsobí a tím pádem lehce přehlídnete i zásadní chybu, která se bude bez hlášení jenom těžko hledat. Naopak výhodné to může být na serveru, kde máte umístěn web v ostrém provozu, protože když se nezobrazují chybová hlášení, je menší riziko útoku, neboť útočník snadněji přehlídne zranitelnost.

      Výchozí hodnota je u error_reporting nastavena na hodnotu sedm (error_reporting(7)), což způsobuje právě zobrazování pouze E_PARSE, E_WARNING, E_ERROR. Defaultní hodnotu dostaneme taktéž zavoláním funkce bez parametru (error_reporting()).

      Poslední způsob jak vypsat parametr je kombinací předešlých dvou způsobů, kdy můžeme kombinovat bitové masky s názvem úrovně chyby a využívat k němu operátorů.

      Potlačení chybových hlášení

      Při práci se vám určitě stalo, že jste chtěli zabezpečit nějakou funkci, ale ona pořád hlásí chybu, i když se snažíte jak snažíte. Typická ukázka může být otevření souboru, který neexistuje, nebo připojení k databázi, které se nezdaří:

      Na první pohled vypadá že je vše ošetřeno a nemůže nastat žádná chyba. Ovšem, pokud soubor neexistuje, bude parser neustále hlásit chybu i když je celé otevírání v podmínce if. Chyba bude typu WARNING a na výstupu dostaneme:

      Prvním způsobem, jak dosáhnout aby se hlášení o chybách nevypisovaly je nastavit pomocí nám již známého error_reporting úrovně výpisu:

      ale tento způsob je dost nepraktický, neboť se potom vztahuje na celý skript a hlavně v průběhu ladění, kde chceme aby se nám vypisovali všechna chybová hlášení bychom museli hodnotu měnit.

      Naštěstí nám PHP nabízí řešení ve tvaru potlačení chybových hlášení. Řešení spočívá v operátoru “@”. Zavináč potom stačí umístit na začátek řádku, kde nám parser vypisuje chybová hlášení a jeho výpis bude potlačen:

      V případě neúspěchu se nyní vypíše pouze text uvedený v print. To ale neznamená že funkce i v případě úspěchu vrací FALSE hodnotu. Opak je pravdou. Funkce vrací stejnou hodnotu, jako kdyby řádek neobsahoval operátor zavináče.

      Časté chyby

      V PHP se objevují chyby, kterých se dopouští snad každý začínající programátor a většinou neví jak chybu odstranit. První z těchto častých chyb je odesílání header informací pomocí funkce Leader ze špatného místa scriptu. Při práci s touto funkcí jste se určitě někdy setkali s hlášením typu:

      Parser nám tím sděluje, že nemůže modifikovat Header informace. Header informace se totiž musí odesílat před jakýmkoli výstupem stránky. Pokud se této chyby chcete vyvarovat, musíte zabránit jakémukoli výstupu. Tyto chyby často vznikají při includování, kdy do skriptu jednoduše vložíte kód, který již něco vypisuje. Bohužel jako výstup se zde myslí i prázdné znaky jako je mezera, nebo tabulátor, takže je nutné se vyvarovat všecho.

      Poslední chybové hlášení, které si rozebereme a se kterým jste se již v praxi určitě setkali je:

      Chyba nastává v případě, že je doba vykonáváni skriptu delší než je na serveru nastaveno – v našem případě 30 sekund, což je většinou nastaveno na všech serverech. Delší doby můžeme dosáhnout velmi snadno a proto, když si budeme vědomi, že skript se může provádět déle, musíme tomuto zabránit. PHP nám zase nabízí řešení v podobě funkce set_time_limit. Pomocí této funkce můžeme ovlivnit dobu provádění skriptu. Jako parametr funkce se udává čas v sekundách:

      Chybová hlášení v MySQL

      Stejně jako nás webový server dokáže informovat o chybách, tak dokáže informovat o chybách i databázový server. Jedná se většinou o chyby, které vznikají při provádění příkazu na databázi a z nějakého důvodu se nemohou vykonat.

      Chyb, proč se příkaz neprovede, může být celá spousta a pokud chceme znát původ chyby, je pro nás nejjednodušší si nechat vypsat chybové hlášení. Databázový server MySQL má, stejně jako webový server Apache, přehledně zpracována chybová hlášení a můžeme z nich většinou na první pohled poznat důvod, nebo příčinu chyby.

      Pro výpis chybových hlášení z MySQL databáze můžeme v PHP využít dvou příkazů, které PHP podporuje již od verze PHP 3:

      • mysql_errno – vrací číslo chyby, která byla způsobena v příkazu
      • mysql_error – vrací chybové hlášení vyvolané příkazem

      Při používání těchto dvou funkcí je důležité si uvědomit, že funkce vrací chybové zprávy vztahující se jenom k jednomu, poslednímu vykonanému příkazu na databázi. Při použití musíme tedy kontrolovat obsah chybové zprávy vždy před voláním dalšího příkazu.

      V praxi potom celá operace výpisu chybových zpráv může vypadat:

      V dotazu na databázi se pokusíme vybrat data. Bohužel se nám stalo, že jsme špatně napsali název tabulky a tabulka neexistuje. Pokud bychom si nenechali vypsat chybové hlášení, těžko bychom hledali proč se dotaz nevykonal správně, hlavně jednalo by se o nepatrný překlep, který není na první pohled vidět.

      V tomto případě nám dá databázový server přesně vědět co se stalo a proč se dotaz nevykonal:

      Z chybového hlášení mysql_error() je na první pohled jasné co se stalo. Tabulka neexistující_tabulka v databázi data neexistuje. Nyní není problém dotaz opravit bez zbytečného hledání chyby v PHP kódu.

      Všimněte si, že v případě chybného dotazu na databázi není vyvoláno v PHP žádné chybové hlášení, ba dokonce ani WARNING, proto je nutné aby sám programátor tyto zbytečné chyby hlídal a ošetřoval.

      Vlastní řešení chybových hlášení

      Při práci můžeme narazit na situaci, kdy bychom chtěli chybu ošetřit jinak, než ji ošetří parser. I tuto možnost PHP nabízí v podobě několika funkcí:

      trigger_error

      Funkce trigger_error slouží k vytvoření vlastní chyby, kterou by parser neošetřil. Může se nám stát, že za určitě situace chceme mít kód pod kontrolou takovým způsobem, že vytvoříme vlastní chybová hlášení při nesplnění nějaké podmínky. Při vytváření chybového hlášení máme k dispozici ze tří úrovní:

      • E_USER_ERROR – vytvoří chybové hlášení s prioritou E_ERROR
      • E_USER_WARNING – vytvoří chybové hlášení s prioritou E_WARNING
      • E_USER_NOTICE – vytvoří chybové hlášení s prioritou E_NOTICE

      Další parametr, který musí funkce obsahovat je chybové hlášení, jež se bude vypisovat na výstupu.
      V praxi můžeme tuto funkci použít podobně tomuto příkladu:

      Jestliže nebude definována proměnná $a, dostaneme jako výstup chybové hlášení s prioritou NOTICE:

      set_error_handler

      Další funkcí, kterou můžeme ovlivňovat způsob výpisu chybových hlášení je funkce set_error_handler. Funkce umožňuje úplně měnit chybová hlášení, která parser produkuje jako výstup. Funkce umí tato chybová hlášení zpracovat podle přání programátora.

      Použití je velmi jednoduché, vytvoříme si funkci, která bude naše chybová hlášení zpracovávat, a aplikujeme ji pomocí set_error_handler:

      Pokud je funkce nastavena, předávají se jí čtyři parametry:

      • číslo chyby – je to bitová maska chyby
      • zpráva – je to zpráva, kterou zasílá jako chybu
      • soubor – soubor, ve kterém se chyba vyskytla
      • řádek – číslo řádku na kterém se chyba nachází

      Nyní již stačí vytvořit funkci MojeOsetreniChyb a nechat ji zpracovávat chybová hlášení:

      Pokud se podíváte na konec skriptu, udělali jsme úmyslně několik chyb:

      • chyba je vytvořena pomocí trigger_error. Chyba je typu E_USER_ERROR, porto ji musíme nadefinovat jako E_WARNING, jinak by ji naše funkce zpracovala jako UNDEFINED.
      • chyba je vytvořena pomocí funkce fopen, která se pokouší číst neexistující soubor.
      • Notice chyba způsobená neexistující proměnnou.
      • funkcemi fread a fclose. Soubor se nepodařilo otevřít, takže i tyto funkce budou vykazovat WARNING

      Na výstupu dostaneme:

Comments are closed for this page

doporucuji na jeste lepsi chyby nainstalovat na ladeni xdebug

Dobrá práce, takovýhle přehled se šikne, když člověk přemýšlí nad chybou.

About
Hi, i am programmer from the Czech Republic. I love web development (Ruby, Ruby on Rails, PHP, Nette) and iOS development (Objective-C, Cocoa).
To cooperate, here is my phone:
+420 608 836