Как я могу обрабатывать синтаксический анализ и фатальных ошибок с помощью обработчика ошибок custom?
PHP: пользовательский обработчик ошибок - обработка синтаксических ошибок и фатальных ошибок
Ответ 1
Простой ответ: вы не можете. См. manual:
Следующие типы ошибок не могут быть обрабатывается с помощью определенной пользователем функции: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING и большинство E_STRICT поднят в файле, где Вызывается set_error_handler().
Для каждой другой ошибки вы можете использовать set_error_handler()
EDIT:
Так как кажется, что есть несколько дискуссий по этой теме, в отношении использования register_shutdown_function
, мы должны взглянуть на определение обработки: для меня обработка ошибки означает ловить ошибку и реагировать таким образом это "хорошо" для пользователя и базовых данных (базы данных, файлы, веб-службы и т.д.).
Используя register_shutdown_function
, вы не можете обрабатывать ошибку из кода, в котором он был вызван, что означает, что код все равно перестанет работать в точке, где происходит ошибка. Однако вы можете представить пользователю сообщение об ошибке вместо белой страницы, но вы не можете, например, отбросить все, что ваш код сделал до сбоя.
Ответ 2
На самом деле вы можете обрабатывать синтаксические и фатальные ошибки. Верно, что функция обработчика ошибок, которую вы определили с помощью set_error_handler(), не будет вызываться. Способ сделать это - определить функцию выключения с помощью register_shutdown_function(). Вот что я работаю на своем веб-сайте:
Файл prepend.php (этот файл будет автоматически добавлен ко всем скриптам php). Ниже приведены советы по добавлению файлов в PHP.
set_error_handler("errorHandler");
register_shutdown_function("shutdownHandler");
function errorHandler($error_level, $error_message, $error_file, $error_line, $error_context)
{
$error = "lvl: " . $error_level . " | msg:" . $error_message . " | file:" . $error_file . " | ln:" . $error_line;
switch ($error_level) {
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_PARSE:
mylog($error, "fatal");
break;
case E_USER_ERROR:
case E_RECOVERABLE_ERROR:
mylog($error, "error");
break;
case E_WARNING:
case E_CORE_WARNING:
case E_COMPILE_WARNING:
case E_USER_WARNING:
mylog($error, "warn");
break;
case E_NOTICE:
case E_USER_NOTICE:
mylog($error, "info");
break;
case E_STRICT:
mylog($error, "debug");
break;
default:
mylog($error, "warn");
}
}
function shutdownHandler() //will be called when PHP скрипт ends.
{
$lasterror = error_get_last();
switch ($lasterror['type'])
{
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
case E_RECOVERABLE_ERROR:
case E_CORE_WARNING:
case E_COMPILE_WARNING:
case E_PARSE:
$error = "[SHUTDOWN] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line'];
mylog($error, "fatal");
}
}
function mylog($error, $errlvl)
{
...do whatever you want...
}
PHP вызовет функцию errorHandler(), если он поймает ошибку в любом из скриптов. Если ошибка немедленно отключает script, ошибка обрабатывается функцией shutdownHandler().
Это работает на сайте, который я разрабатываю. Я еще не тестировал его на производстве. Но в настоящее время он ловит все ошибки, которые я нахожу при разработке.
Я считаю, что есть риск дважды поймать одну и ту же ошибку, по каждой функции. Это может произойти, если ошибка, которую я обрабатываю в функции shutdownHandler(), также была обнаружена функцией errorHandler().
TODO-х:
1 - Мне нужно работать с лучшей функцией log(), чтобы обрабатывать ошибки изящно. Поскольку я все еще в разработке, я в основном регистрирую ошибку в базе данных и повторяю ее на экране.
2 - Внедрить обработку ошибок для всех вызовов MySQL.
3 - Внедрить обработку ошибок для моего кода javascript.
ВАЖНЫЕ ПРИМЕЧАНИЯ:
1 - Я использую следующую строку в своем php.ini для автоматического добавления вышеприведенного script ко всем php-скриптам:
auto_prepend_file = "/homepages/45/d301354504/htdocs/hmsee/cgi-bin/errorhandling.php"
он работает хорошо.
2 - Я регистрирую и разрешаю все ошибки, включая ошибки E_STRICT. Я верю в разработку чистого кода. Во время разработки мой файл php.ini имеет следующие строки:
track_errors = 1
display_errors = 1
error_reporting = 2147483647
html_errors = 0
Когда я буду жить, я изменил display_errors на 0, чтобы уменьшить риск того, что мои пользователи будут видеть уродливые сообщения об ошибках PHP.
Я надеюсь, что это поможет кому-то.
Ответ 3
Вы можете отслеживать эти ошибки, используя следующий код:
(Ошибки анализа могут быть обнаружены только в том случае, если они встречаются в других файлах script через include()
или require()
, или помещая этот код в auto_prepend_file
, как упомянули другие ответы.)
function shutdown() {
$isError = false;
if ($error = error_get_last()){
switch($error['type']){
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
$isError = true;
break;
}
}
if ($isError){
var_dump ($error);//do whatever you need with it
}
}
register_shutdown_function('shutdown');
Ответ 4
Из комментариев PHP.net на странице http://www.php.net/manual/en/function.set-error-handler.php
Я понял, что несколько человек здесь упомянули, что вы не можете захватить ошибки разбора (тип 4, E_PARSE). Это неправда. Вот как я это делаю. Я надеюсь, что это помогает кому-то.
1) Создайте файл auto_prepend.php в корневом каталоге веб-сайта и добавьте следующее:
<?php
register_shutdown_function('error_alert');
function error_alert()
{
if(is_null($e = error_get_last()) === false)
{
mail('[email protected]', 'Error from auto_prepend', print_r($e, true));
}
}
?>
2) Затем добавьте это значение "php_value auto_prepend_file /www/auto _prepend.php" на ваш .htaccess в корневом каталоге.
- убедитесь, что вы изменили адрес электронной почты и путь к файлу.
Ответ 5
Ошибка script с ошибкой синтаксического разбора всегда прерывается и ее невозможно обработать. Поэтому, если script вызывается напрямую или включает/требует, вы ничего не можете сделать. Но если он вызывается AJAX, flash или любым другим способом, там есть обходной способ обнаружения ошибок синтаксического анализа.
Мне понадобилось это для обработки swfupload script. Swfupload - это флеш-память, которая обрабатывает загрузку файлов и загружается каждый раз, она вызывает обработку PHP script для обработки filedata - но нет вывода для браузера, поэтому для обработки PHP скрипт необходимы эти параметры для целей отладки:
- предупреждения и уведомления ob_start(); в начале и сохранить содержимое в сеансе ob_get_contents(); в конце обработки script: это может отображаться в браузере другим script
- фатальные ошибки register_shutdown_function(), чтобы установить сеанс с тем же трюком, что и выше
- анализировать ошибки, если ob_get_contents() находится в конце обработки script и ранее была обнаружена ошибка синтаксиса, сессия не заполнена (она равна нулю). Отладка script может обрабатывать ее следующим образом:
if(!isset($_SESSION["swfupload"])) echo "parse error";
Примечание 1 null
означает is not set
- isset()
Ответ 6
Из моего опыта вы можете поймать все типы ошибок, скрыть сообщение об ошибке по умолчанию и отобразить собственное сообщение об ошибке (если хотите). Ниже перечислены то, что вам нужно.
1) Начальный/верхний уровень script, назовем его index.php
, где вы храните свои пользовательские функции обработчика ошибок. Пользовательские обработчики функций ошибок должны оставаться наверху, поэтому они подхватывают ошибки под ними, "ниже", я имею в виду вложенные файлы.
2) Предположим, что это верхняя ошибка script является ошибкой! это очень важно, вы не можете обнаружить фатальные ошибки в index.php
, когда ваша пользовательская функция обработчика ошибок находится в index.php
.
3) Директивы Php (также должны быть найдены в index.php
)
set_error_handler("myNonFatalErrorHandler");
#, чтобы поймать нефатальные ошибки
register_shutdown_function('myShutdown');
# в целях обнаружения фатальных ошибок
ini_set('display_errors', false);
#, чтобы скрыть ошибки, отображаемые пользователю по php
ini_set('log_errors',FALSE);
#assuming, мы регистрируем ошибки сами
ini_set('error_reporting', E_ALL);
# Нам нравится сообщать обо всех ошибках
во время производства (если я не ошибаюсь), мы можем оставить ini_set('error_reporting', E_ALL);
как есть, чтобы иметь возможность регистрировать ошибку, в то же время ini_set('display_errors', false);
будет гарантировать, что пользователю не будут отображаться ошибки.
Что касается фактического содержания двух функций, о которых я говорю, myNonFatalErrorHandler
и myShutdown
, я не размещаю подробный контент здесь, чтобы все было просто. Кроме того, другие посетители дали множество примеров. Я просто показываю очень простую идею.
function myNonFatalErrorHandler($v, $m, $f, $l, $c){
$some_logging_var_arr1[]="format $v, $m, $f, ".$err_lvl[$l].", $c the way you like";
//You can display the content of $some_logging_var_arr1 at the end of execution too.
}
function myShutdown()
{
if( ($e=error_get_last())!==null ){
$some_logging_var_arr2= "Format the way you like:". $err_level[$e['type']].$e['message'].$e['file'].$e['line'];
}
//display $some_logging_var_arr2 now or later, e.g. from a custom session close function
}
как для $err_lvl это может быть:
$err_lvl = array(E_ERROR=>'E_ERROR', E_CORE_ERROR=>'E_CORE_ERROR', E_COMPILE_ERROR=>'E_COMPILE_ERROR', E_USER_ERROR=>'E_USER_ERROR', E_PARSE=>'E_PARSE', E_RECOVERABLE_ERROR=>'E_RECOVERABLE_ERROR', E_WARNING=>'E_WARNING', E_CORE_WARNING=>'E_CORE_WARNING', E_COMPILE_WARNING=>'E_COMPILE_WARNING',
E_USER_WARNING=>'E_USER_WARNING', E_NOTICE=>'E_NOTICE', E_USER_NOTICE=>'E_USER_NOTICE',E_STRICT=>'E_STRICT');