【问题标题】:Preventing Exceptions without Stack Frames with Error Exception Handler and Shutdown Sequences使用错误异常处理程序和关闭序列防止没有堆栈帧的异常
【发布时间】:2012-12-15 17:43:36
【问题描述】:

这周我遇到了一些小问题。前面的错误消息是关于:

[2012 年 12 月 30 日 15:19:32] PHP 致命错误:在第 0 行的未知中抛出没有堆栈帧的异常

我认为这是因为我的错误处理程序(详见下文)正在将任何错误转化为异常。如果没有堆栈框架,我可能应该阻止这种情况。

有没有一种简单的方法可以找出 PHP 中是否有任何堆栈帧?

详情:

在我的一个网站上,我运行了一个错误处理程序,它将每个错误都转换为异常,准确地说是常见的ErrorException

我前段时间介绍了它,因为该站点主要是遗留代码,我希望有任何问题导致异常,我最终可以以简化的方式“捕获”异常处理程序并停止请求。

我把它放到它自己的类中,注册处理程序,同时打开一个输出缓冲区来捕获输出,直到抛出异常。基本上是这样的代码:

// register output buffering
$r = ob_start(array($this, 'handleBuffer'));

// register error handler       
$this->_originalErrorHandler = set_error_handler(array($this, 'handleError'));

// register exception handler
$this->_originalExceptionHandler = set_exception_handler(array($this, 'handleException'));

在我决定添加另一个输出缓冲类之前,这一切都很好。只有一个能够捕获所有输出,然后可以在网站上进行一些“后期制作”,包括检查 HTML 问题(是的,这都有点遗留,所以实际上这有点老套,我知道)。顺便说一句,这也很好用。但是当我在新组件中犯了一个错误时不会:

[2012 年 12 月 30 日 15:19:32] PHP 致命错误:在第 0 行的未知中抛出没有堆栈帧的异常

这基本上是我的问题。有没有一种简单的方法可以防止出现这些错误?我有点知道为什么会出现错误,但我不太确定,所以我很难真正规避这个问题。我试图在脚本进入新的关闭阶段之前释放新的输出缓冲区,因为我认为这会导致这种情况。但这并没有成功。

【问题讨论】:

    标签: error-handling shutdown php


    【解决方案1】:

    您的问题表明您正在使用 PHP 的 EOL (End Of Life) 版本(特别是 PHP

    这可能是由几个不同的原因造成的。一些最常见的如下:

    1. 您从错误处理程序或异常处理程序内部引发了异常。
    2. 您从析构函数内部引发了异常。
    3. 您从回调内部引发了异常(如输出缓冲回调函数)。

    这是一个示例,可以说明您在某些情况下遇到的问题...

    function myErrorHandler($errno, $errstr, $errfile, $errline)
    {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }
    
    function myExceptionHandler($exception) {
        echo "We got an exception with message: '{$exception->getMessage()}'";
    }
    
    function myCallBack($contents) {
        trigger_error('ohnoes!'); // You can't throw an error from the output buffer callback function in older versions of PHP < 5.3
    }
    
    class Foo {
        public function __destruct() {
            trigger_error('ohnoes!'); // You can't throw an error from a destructor in older versions of PHP < 5.3
        }
    }
    
    set_error_handler('myErrorHandler');
    set_exception_handler('myExceptionHandler');
    

    上面的代码会导致您看到您在此处描述的致命错误...

    ob_start("myCallBack");
    

    ...这里...

    $foo = new foo;
    

    此问题已在 PHP >= 5.3.0 中得到修复,因此如果您使用的是最新版本的 PHP,您应该不会看到此问题。

    最简单的解决方法是升级您的 PHP。如果这不是一个选项,您必须考虑这些事实,即您不能在 PHP 不期望它们被抛出的地方抛出异常(在回调函数、错误处理程序、异常处理程序等中...... - 实际上所有这些都被认为是PHP 的回调)。

    另一件事是您不应该以这种方式将每个错误都变成异常。如果您所做的与我提供的代码一样(即从错误处理程序内部抛出异常——从而将每个错误都变成异常),那么您将给自己带来很多的痛苦而且几乎没有任何好处。 PHP 错误不应该被处理。它们旨在通知客户问题(客户是编写 PHP 代码的人)或潜在问题。处理错误本身并不像将每个错误都变成异常然后处理该异常那么简单,因为并非每个错误都应该是异常的。例如,E_NOTICE 级别的错误在异常处理中没有位置。它们主要用于通知您潜在的错误,而不是您的代码一定有错误,更不用说它们中的大多数甚至无法在用户空间代码中轻松处理(它们大多需要重新分解代码本身)。 我强烈建议不要使用这种糟糕的做法

    【讨论】:

    • 哇,你是对的,在那台服务器上运行 PHP 5.2,一些较旧的 Debian 机器。我已经让管理员至少升级到 PHP 5.3,但到目前为止还没有运气。也许新年是一个很好的提醒;)感谢您迄今为止的广泛回答,是的,您是对的,我什至不需要/这样做。也许我可以在异常处理旁边进行错误处理,而不是将错误变成异常。
    • 嗯,我只是问自己是否真的可以概括,将错误转化为异常是一个坏主意。解决 PHP 5.2 的问题(假设是 PHP 5.3 / 5.4)。
    猜你喜欢
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-03
    • 2020-01-04
    相关资源
    最近更新 更多