Jak napsat error handler v PHP?
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ář