Принято ошибочно считать, что фатальные ошибки в PHP (те, что отображаются как Fatal Error) невозможно перехватить и обработать программно. Действительно, в PHP имеется функция set_error_handler(), позволяющая программисту назначить свою собственную функцию-обработчик на нотисы (NOTICE) и предупреждения (WARNING), однако она не может перехватить управление при наступлении фатальной ошибки например, вызове неопределенной функции:
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
echo "Error $errno happened! $errstr on $errfile line $errline";
return true;
}
// Set an error handler for warnings and notices.
set_error_handler('myErrorHandler');
// Generate a notice.
echo $nonExistedVariable;
// Generate a fatal error.
callToUndefinedFunction();
Запустив этот пример, вы увидите, что перехватчик myErrorHandler() вызвался для первой ошибки (NOTICE), но вторая ошибка (ERROR) не была им обработана, а отобразилась в браузере в стандартном виде.
Написано в 2009 году (касается новых версий PHP):
- Кстати, функция-финализатор, назначенная вызовом register_shutdown_function, прекрасно вызывается в случае фатальной ошибки.
Написано в 2007 году (касается старых версий PHP):
- Кстати, назначенные по register_shutdown_function функции-финализаторы скрипта не вызываются при наступлении фатальной ошибки.
Тем не менее, способ вызвать PHP-код при наступлении фатальной ошибки все же существует. Для этого следует назначить обработчик выходного потока через ob_start() он будет вызван в любом случае, даже если программа завершилась аварийно:
function myObHandler($str)
{
return $str . " - output is handled!";
}
// Handle the output stream and set a handler function.
ob_start('myObHandler');
// Generate a fatal error.
callToUndefinedFunction();
Вы увидите, что PHP отобразил стандартное сообщение об ошибке, но к нему в конец было приписано " - output is handled!", т.е. наш обработчик сработал.
В разделе сайта Кoнструктор имеется библиотека PHP_CodeFilter, упрощающая перехват ошибок по описанному алгоритму, а также позволяющая делать еще некоторые вещи.
Перехват ошибки нехватки памяти
Метод с ob_start() может иногда не сработать, если произошедшая фатальная ошибка это ошибка нехватки памяти ("Allowed memory size of xxx bytes exhausted"). Она возникает, когда PHP пытается затребовать больше памяти, чем ему разрешено настройкой memory_limit файла php.ini.
К счастью, выход есть и в этом случае (правда, он работает не в 100% ситуаций, а только если память выделяется относительно большими кусками):
function myObHandler($str)
{
// Free a piece of memory.
unset($GLOBALS['tmp_buf']);
// Now we have additional 100K of memory, so - continue to work.
return $str . " - output is handled!";
}
// Reserve 200K of memory for emergency needs.
$GLOBALS['tmp_buf'] = str_repeat('x', 1024 * 200);
// Handle the output stream and set a handler function.
ob_start('myObHandler');
// Simulate a memory limit error.
echo str_repeat("Test string!<br>", 500);
while(1) $tmp[] = str_repeat('a', 10000);
Итак, мы резервируем некоторый объем памяти во временной переменной, которую освобождаем в первой строке обработчика выходного потока. При этом высвобождается некоторое количество памяти, которого должно хватить на корректное продолжение работы обработчика (он сам по себе может потреблять сколько-то памяти).
Таким образом, можно сделать следующее заключение: при наступлении ошибки memory_limit PHP честно пытается запустить обработчик, однако, если в процессе его работы опять не хватит памяти, выполнение скрипта останавливается уже окончательно. Освободив 200К памяти в самом начале обработчика, мы оказываемся практически застрахованными от такой ситуации.
Нужно понимать, что этот метод работает при условии, что память закончилась при выделении достаточно крупного куска (в нашем случае - 10К). В противном случае PHP может не хватить ресурсов даже на то, чтобы просто инициировать запуск обработчика выходного потока.
автор категорически против копирования и распространения в Интернете всех статей «Куроводства» с возрастом, меньшим 6 месяцев. Печальный опыт «расползания» чрезвычайно устаревших ошибочных версий статьи про Apacheдействительно объясняет такое решение.
Орфография на «Куроводстве»:
если вы заметили орфографическую, стилистическую или другую ошибку на этой странице, просто выделите ошибку мышью и нажмитеCtrl+Enter. Выделенный текст будет немедленно отослан вебмастеру, а Вы даже ничего и не заметите настолько быстро все произойдет.
На заметку:
если вы уже вскипели насчет дизайна этой страницы, то присмотритесь повнимательнее к названию, почитайте FAQ, сходите , как это уже предлагалось выше. Можно ли считать пародию плагиатом? Надеюсь, что нет.