42

根据对此答案的评论,可以通过无法捕获的关闭功能捕获致命错误set_error_handler()

但是,我无法确定如何确定关闭是由于致命错误还是由于脚本到达结尾而发生的。

此外,调试回溯功能似乎在关闭功能中失效,使得记录致命错误发生的堆栈跟踪变得毫无价值。

所以我的问题是:什么是对致命错误(尤其是未定义的函数调用)做出反应的最佳方式,同时保持创建适当回溯的能力?

4

3 回答 3

75

这对我有用:

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 中恢复。

至于回溯,你不能...... :(在大多数致命错误的情况下,尤其是未定义的函数错误,你并不真正需要它。查明它发生的文件/行就足够了。回溯是无关紧要的在这种情况下。

于 2010-12-10T16:05:55.617 回答
11

使用 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 页面,这样您就不会只提供空白页面。

于 2013-01-10T08:13:59.327 回答
7

获取当前 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 停止显示错误,否则错误文本将在您的错误处理程序之前发送到客户端

于 2013-09-12T08:05:02.163 回答