Как я могу поймать PHP фатальную ошибку - PullRequest
526 голосов
/ 10 ноября 2008

Я могу использовать set_error_handler() для перехвата большинства ошибок PHP, но это не работает для фатальных (E_ERROR) ошибок, таких как вызов несуществующей функции. Есть ли другой способ отловить эти ошибки?

Я пытаюсь вызвать mail() для всех ошибок и использую PHP 5.2.3.

Ответы [ 18 ]

8 голосов
/ 20 октября 2011

Мне нужно обработать фатальные ошибки для производства, чтобы вместо этого показать статический стиль 503 Сервис недоступен для вывода HTML. Это, безусловно, разумный подход к «выявлению фатальных ошибок». Вот что я сделал:

У меня есть пользовательская функция обработки ошибок "error_handler", которая будет отображать мою HTML-страницу "503 служба недоступна" на любом E_ERROR, E_USER_ERROR и т. Д. Теперь она будет вызываться для функции завершения работы с обнаружением моей фатальной ошибки.

function fatal_error_handler() {

    if (@is_array($e = @error_get_last())) {
        $code = isset($e['type']) ? $e['type'] : 0;
        $msg = isset($e['message']) ? $e['message'] : '';
        $file = isset($e['file']) ? $e['file'] : '';
        $line = isset($e['line']) ? $e['line'] : '';
        if ($code>0) error_handler($code,$msg,$file,$line);
    }
}
set_error_handler("error_handler");
register_shutdown_function('fatal_error_handler');

в моей пользовательской функции error_handler, если ошибка E_ERROR или E_USER_ERROR и т. Д. Я также вызываю @ob_end_clean (); очистить буфер, удалив таким образом PHP сообщение «фатальная ошибка».

Обратите внимание на строгую проверку isset () и функции @ silencing, поскольку мы не хотим, чтобы наши скрипты error_handler генерировали какие-либо ошибки.

Соглашаясь с keparo, обнаружение фатальных ошибок лишает цели «ФАТАЛЬНОЙ ошибки», поэтому она не предназначена для дальнейшей обработки. Не запускайте никакие функции mail () в этом процессе выключения, так как вы обязательно создадите резервную копию почтового сервера или вашего почтового ящика. Вместо этого запишите эти случаи в файл и запланируйте cron, чтобы найти эти файлы error.log и отправьте их по почте администраторам.

7 голосов
/ 03 мая 2012

В PHP обнаруживаются фатальные ошибки. Они определены как E_RECOVERABLE_ERROR. Руководство по PHP описывает E_RECOVERABLE_ERROR как:

Исправляемая фатальная ошибка. Это указывает на то, что, возможно, произошла опасная ошибка, но двигатель не работал нестабильно. Если ошибка не обнаружена пользовательским дескриптором (см. Также set_error_handler () ), приложение прерывается, как и E_ERROR.

Вы можете «перехватить» эти «фатальные» ошибки, используя set_error_handler () и проверяя E_RECOVERABLE_ERROR. Я считаю полезным генерировать исключение при обнаружении этой ошибки, тогда вы можете использовать try / catch.

Этот вопрос и ответ содержит полезный пример: Как я могу поймать "поддающуюся фатальной ошибке" подсказку типа PHP?

Ошибки E_ERROR, однако, могут быть обработаны, но не могут быть восстановлены, поскольку двигатель находится в нестабильном состоянии.

5 голосов
/ 09 ноября 2014

Поскольку большинство ответов здесь излишне многословны, вот моя не уродливая версия ответа с наибольшим количеством голосов:

function errorHandler($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array()) {
    //Do stuff: mail, log, etc
}

function fatalHandler() {
    $error = error_get_last();
    if($error) errorHandler($error["type"], $error["message"], $error["file"], $error["line"]);
}

set_error_handler("errorHandler")
register_shutdown_function("fatalHandler");
5 голосов
/ 27 июня 2013

Просто хороший трюк, чтобы получить текущий метод error_handler =)

<?php
register_shutdown_function('__fatalHandler');
function __fatalHandler()
{
    $error      = error_get_last();

    //check if it's a core/fatal error, otherwise it's a normal shutdown
    if($error !== NULL && $error['type'] === E_ERROR) {
        //Bit hackish, but the set_exception_handler will return the old handler
        function fakeHandler() { }
        $handler = set_exception_handler('fakeHandler');
        restore_exception_handler();
        if($handler !== null) { 
            call_user_func($handler, new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
        }
        exit;
    }
}
?>

Также я не хочу отметить, что если вы позвоните

<?php
ini_set('display_errors', false);
?>

Php перестает отображать ошибку, иначе текст ошибки будет отправлен клиенту до вашего обработчика ошибок

4 голосов
/ 10 ноября 2008

Не совсем. Так называются фатальные ошибки, потому что они фатальны. Вы не можете оправиться от них.

3 голосов
/ 21 декабря 2012

Существуют определенные обстоятельства, в которых должны быть обнаружены даже фатальные ошибки (вам может потребоваться выполнить некоторую очистку, прежде чем выйти изящно и не просто умереть ...). Я реализовал хук pre_system в моих приложениях codeigniter, чтобы я мог получать фатальные ошибки по электронной почте, и это помогло мне найти ошибки, о которых не сообщалось (или о которых сообщалось после их исправления, поскольку я уже знал о них :)). Почтовый ящик проверяет, не было ли уже сообщено об ошибке, чтобы она не доставляла вам спам с известными ошибками несколько раз.

<code>class PHPFatalError {

    public function setHandler() {
        register_shutdown_function('handleShutdown');
    }

}

function handleShutdown() {
    if (($error = error_get_last())) {
        ob_start();
        echo "<pre>";
        var_dump($error);
        echo "
"; $ message = ob_get_clean (); SendEmail ($ сообщение); ob_start (); echo '{"status": "error", "message": "Внутренняя ошибка приложения!"}'; ob_flush (); выход(); } }
2 голосов
/ 09 ноября 2011

Я разработал эту функцию, чтобы сделать возможным «песочницу» кода, который может привести к фатальной ошибке. Поскольку исключения, выбрасываемые из замыкания register_shutdown_function, не передаются из стека вызовов до фатальной ошибки, я вынужден выйти после этой функции, чтобы обеспечить единообразный способ ее использования.

function superTryCatchFinallyAndExit( Closure $try, Closure $catch = NULL, Closure $finally )
{
    $finished = FALSE;
    register_shutdown_function( function() use ( &$finished, $catch, $finally ) {
        if( ! $finished ) {
            $finished = TRUE;
            print "EXPLODE!".PHP_EOL;
            if( $catch ) {
                superTryCatchFinallyAndExit( function() use ( $catch ) {
                    $catch( new Exception( "Fatal Error!!!" ) );
                }, NULL, $finally );                
            } else {
                $finally();                
            }
        }
    } );
    try {
        $try();
    } catch( Exception $e ) {
        if( $catch ) {
            try {
                $catch( $e );
            } catch( Exception $e ) {}
        }
    }
    $finished = TRUE;
    $finally();
    exit();
}
1 голос
/ 01 декабря 2014

Я написал Q & A в стиле Wiki с полным решением для обнаружения всех ошибок в PHP; которые можно посмотреть / почитать / украсть / критиковать здесь .

Решение включает в себя 5 методов, которые обертывают все ошибки, которые может генерировать PHP, которые в конечном итоге передают указанные ошибки в типизированный объект ErrorHandler.

Надеюсь, некоторым людям это пригодится. Даже если вы не украдете его напрямую, я уверен, что решение является, по крайней мере, хорошим примером того, как обрабатывать ошибки в PHP - во всех отношениях.

@ Лукас Батистусси получил очки за креативность - я думаю, что я мог бы также поделиться своим решением и стрелять по некоторым подобным пунктам ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...