Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу).
Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу). Внимание! Прочитайте, пожалуйста, текст в правой колонке (внизу). Homepage Карта сайта Версия для печати

Джентльменский набор Web-разработчика   Ларри Уолл о Perl6   Наблы Система Orphus
 

45. Про перехват и обработку фатальных ошибок (Fatal Error) в PHP

[5 августа 2007 г.] обсудить статью в форуме

Принято ошибочно считать, что фатальные ошибки в PHP (те, что отображаются как Fatal Error) невозможно перехватить и обработать программно. Действительно, в PHP имеется функция set_error_handler(), позволяющая программисту назначить свою собственную функцию-обработчик на нотисы (NOTICE) и предупреждения (WARNING), однако она не может перехватить управление при наступлении фатальной ошибки — например, вызове неопределенной функции:

Листинг 1
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() — он будет вызван в любом случае, даже если программа завершилась аварийно:

Листинг 2
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% ситуаций, а только если память выделяется относительно большими кусками):

Листинг 3
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 может не хватить ресурсов даже на то, чтобы просто инициировать запуск обработчика выходного потока.

обсудить статью в форуме

 
Рекламный блок
   

На странице:
    45. Про перехват и обработку фатальных ошибок (Fatal Error) в PHP
Перехват ошибки нехватки памяти

Важное объявление:
    автор категорически против копирования и распространения в Интернете всех статей «Куроводства» с возрастом, меньшим 6 месяцев. Печальный опыт «расползания» чрезвычайно устаревших ошибочных версий статьи про Apache действительно объясняет такое решение.

Орфография на «Куроводстве»:
    если вы заметили орфографическую, стилистическую или другую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Выделенный текст будет немедленно отослан вебмастеру, а Вы даже ничего и не заметите — настолько быстро все произойдет.

На заметку:
    если вы уже вскипели насчет дизайна этой страницы, то присмотритесь повнимательнее к названию, почитайте FAQ, сходите по лебедевским местам, как это уже предлагалось выше. Можно ли считать пародию плагиатом? Надеюсь, что нет.

Параметры этой страницы
   
GZip

Ссылки от спонсоров
   


Дмитрий Котеров | 5 августа 2007 г. ©1999-2016 | Генеральный спонсор: Хостинг «Джино» | Контакт Вернуться к оглавлению