Подтвердить что ты не робот

Управлять фатальными ошибками в PHP с помощью register_shutdown_function()

В соответствии с комментарием к этому ответу можно обнаружить Fatal Errors через shutdown функция, которая не может быть обнаружена с помощью set_error_handler().

Однако я не мог узнать, как определить, произошло ли завершение из-за фатальной ошибки или из-за достижения script.

Кроме того, функции отладки backgrace, по-видимому, не функционируют в функции выключения, что делает его довольно бесполезным для регистрации трассировки стека, где произошла Fatal Error.

Итак, мой вопрос: какой лучший способ реагировать на Fatal Errors (особенно вызовы функций undefined), сохраняя при этом способность создавать правильную обратную трассировку?

4b9b3361

Ответ 1

Это работает для меня:

function shutdown() {
    $error = error_get_last();
    if ($error['type'] === E_ERROR) {
        // fatal error has occured
    }
}

register_shutdown_function('shutdown');

spl_autoload_register('foo'); 
// throws a LogicException which is not caught, so triggers a E_ERROR

Однако вы, вероятно, уже знаете это, но просто убедитесь, что вы не можете восстановить E_ERROR каким-либо образом.

Что касается backtrace, вы не можете...:( В большинстве случаев фатальной ошибки, особенно ошибок функции Undefined, вам это действительно не нужно. Точное определение файла/строки, где это произошло, достаточно В этом случае обратная трассировка не имеет значения.

Ответ 2

Один из способов отличить фатальную ошибку и правильное завершение работы приложения с функцией register_shutdown_function - определить константу как последнюю строку вашей программы, а затем проверить, определена ли константа:

function fatal_error() {
if ( ! defined(PROGRAM_EXECUTION_SUCCESSFUL)) {
        // fatal error has occurred
    }
}

register_shutdown_function('fatal_error');

define('PROGRAM_EXECUTION_SUCCESSFUL', true);

Если программа достигает конца, она не могла бы столкнуться с фатальной ошибкой, поэтому мы знаем, что она не запускает функцию, если определена константа.

error_get_last() - это массив со всей информацией о фатальной ошибке, которую нужно отлаживать, хотя она не будет иметь обратную трассировку, как было упомянуто.

Как правило, если ваша php-программа столкнулась с фатальной ошибкой (в отличие от исключения), вы хотите, чтобы программа взорвалась, чтобы вы могли найти и устранить проблему. Я нашел register_shutdown_function полезным для производственных сред, где вы хотите, чтобы отчет об ошибках отключился, но хотите каким-то образом зарегистрировать ошибку в фоновом режиме, чтобы вы могли ответить на нее. Вы также можете использовать эту функцию, чтобы направить пользователя на дружественную html-страницу в случае такой ошибки, чтобы не просто показывать пустую страницу.

Ответ 3

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

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

    //check if it a core/fatal error, otherwise it 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

Я использую для этого ob_start.

function fatal_error_handler($buffer) {
    if (preg_match("|(Fatal error:)(.+)|", $buffer, $regs) ) {
        //Your code
    }
    return $buffer;
}
ob_start("fatal_error_handler");