Pokud píšete vlastní error handler pro PHP, je bezpodmínečně nutné dodržet několik pravidel. Jinak může nabourat chování dalších knihoven a aplikací, které nečekají v error handleru zradu.
Parametry
Signatura handleru vypadá takto:
function errorHandler(
int $severity,
string $message,
string $file,
int $line,
array $context = null // pouze v PHP < 8
): ?bool {
...
}
Parametr $severity obsahuje úroveň chyby
(E_NOTICE, E_WARNING, …). Pomocí handleru nelze
zachytávat fatální chyby, jako třeba E_ERROR, takže těchto
hodnot nikdy nebude parametr nabývat. Naštěstí fatální chyby v podstatě
z PHP zmizely a byly nahrazeny za výjimky.
Parametr $message je chybová hláška. Pokud je zapnutá
direktiva html_errors,
jsou speciální znaky jako < apod. zapsány jako HTML entity,
takže do podoby plain textu je musíte dekódovat.
Ovšem pozor, některé znaky jako entity zapsány nejsou, což je bug.
Samotné zobrazování chyb v čistém PHP je tak náchylné na XSS.
Parametry $file a $line představují název
souboru a řádek, kde k chybě došlo. Pokud chyba nastala uvnitř
eval(), bude $file doplněný o tuto informaci.
A nakonec parametr $context obsahuje pole lokálních
proměnných, což představuje pro debugování užitečnou informaci, ale od
PHP 8 je zrušený. Pokud má handler fungovat v PHP 8, parametr vynechte nebo
mu dejte výchozí hodnotu.
Návratová hodnota
Návratová hodnota handleru může být null nebo
false. Pokud handler vrátí null, nestane se nic.
Pokud vrátí false, zavolá se ještě standardní PHP handler.
Ten podle konfigurace PHP může chybu vypsat, zalogovat atd. Co je důležité,
tak že také naplní interní informaci o poslední chybě, kterou
zpřístupňuje funkce error_get_last().
Potlačené chyby
V PHP lze potlačit zobrazování chyb buď pomocí shut-up operátoru
@ nebo pomocí error_reporting():
// potlač chyby úrovně E_USER_DEPRECATED
error_reporting(~E_USER_DEPRECATED);
// potlač všechny chyby při volání fopen()
$file = @fopen($name, 'r');
I při potlačení chyb dojde k volání handleru. Proto je nejprve nutné ověřit, zda chyba je potlačená, a pokud ano, tak musíme vlastní handler ukončit:
if (!($severity & error_reporting())) {
return false;
}
Ale pozor, musíme je v tomto případě ukončit pomocí
return false, aby se spustil ještě standardní error handler. Ten
nic nevypíše ani nezaloguje (protože chyba je potlačená), ale zajistí, že
chybu půjde zjistit pomocí error_get_last().
Ostatní chyby
Pokud náš handler chybu zpracuje (například vypíše vlastní hlášku
atd.), už není potřeba volat standardní handler. Sice pak nebude možné
chybu zjistit pomocí error_get_last(), ale to v praxi nevadí,
protože tato funkce se používá především v kombinaci s shut-up
operátorem.
Pokud handler naopak chybu z jakéhokoliv důvodu nezpracuje, měl by
vrátit false, aby ji nezatajil.
Ukázkový příklad
Takto by vypadal kód vlastního error handleru, který transformuje chyby na výjimky ErrorException:
set_error_handler(function (int $severity, string $message, string $file, int $line) {
if (!(error_reporting() & $severity)) {
return false;
}
throw new \ErrorException($message, 0, $severity, $file, $line);
});
Napište komentář