使用错误异常处理程序和关闭序列防止没有堆栈帧的异常

时间:2012-12-31 16:10:11

标签: error-handling shutdown php

本周我遇到了一个小问题。此前的错误消息是:

  

[30-Dec-2012 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问题(是的,它有点遗留,所以实际上这有点像鸭子,我知道)。这也非常好btw。但是当我在新组件中犯了错误时,不是这样:

  

[30-Dec-2012 15:19:32] PHP致命错误:在第0行的“未知”中没有堆栈帧时抛出异常

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

1 个答案:

答案 0 :(得分:3)

您的问题表明您使用的是 EOL 生命终结)版本的PHP(特别是PHP< 5.3.0),这意味着它不再受支持。这个问题来自抛出没有strack框架的异常,因此旧引擎不知道如何正确处理这些异常。

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

  1. 您从错误处理程序或异常处理程序中抛出异常。
  2. 你从析构函数中抛出异常。
  3. 您从回调内部抛出异常(如输出缓冲回调函数)。
  4. 这是一个在某些情况下证明你的问题的例子......

    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&gt; = 5.3.0中修复,因此如果您使用的是最新版本的PHP,则不应该看到此问题。

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

    另一件事是你不应该以这种方式将每个错误都变成异常。如果你正在做的是我提供的代码演示(即从错误处理程序中抛出一个异常 - 从而将每个错误变成异常)那么你将会让自己很多的痛苦几乎没有任何好处。 PHP错误并不意味着要处理。它们旨在通知客户一个问题(客户端是编写PHP代码的人)或潜在问题。处理错误本身并不像将每个错误转换为异常然后处理该异常那么简单,因为不是每个错误都应该是异常的。例如,E_NOTICE级错误在异常处理中没有位置。它们主要用于通知您潜在的错误,而不是您的代码必然存在错误,更不用说大多数错误甚至无法在用户空间代码中轻松处理(它们通常需要重新分解代码本身)。 我强烈反对这种糟糕的做法