Symfony2异常控制器在出现致命错误时渲染到现有内容中


Symfony2 exception controller renders into existing content in case of Fatal Errors

我在模板的代码中抛出一个异常,在模板末尾的某个地方:

...
{{ offer.throwError() }}
...

报价::throwError:

 public function throwError() {
        $foo = $this->getAdvantageText()->getFoo(); //fatal error
        throw new 'Exception("blah"); //only exception
    }

由于没有定制任何东西,我希望有一个错误页面作为响应(使用Twig的默认ExceptionController,我们实际上想覆盖它)。当Offer::getAdvantageText()为===null时,将引发FatalErrorException,并将错误页面内容直接写入引发异常的位置的标记中。当我只是抛出自定义异常时,它会按预期工作(显示一个错误页面)。当我调试到ExceptionController时,它应该明确地清除输出缓冲区:

Twig/异常控制器:

 protected function getAndCleanOutputBuffering($startObLevel)
    {
        if (ob_get_level() <= $startObLevel) {
            return '';
        }
        Response::closeOutputBuffers($startObLevel + 1, true);
        return ob_get_clean();
    }

但在我所有的致命错误情况下,ob_get_level是<=$startObLevel(由内核移交,在我的例子中是"2")。我们还没有应用程序/网关缓存。在这种情况下,当我手动清除输出缓冲区时,页面被"清除",并且我得到了一个预期的错误页面响应。据我所见,没有任何片段渲染(这会发布一个子任务)。

我曾想过利用kernel.exception事件并自行清除所有内容,但我认为只要自定义控制器就可以了。这个"致命"错误似乎干扰了Symfony内核的ob堆栈,但我不知道如何解决这个问题。

我有一个初步的解决方案来解决这个问题。在我的自定义异常控制器中,我还覆盖了getAndCleanOutputBuffering方法:

protected function getAndCleanOutputBuffering($startObLevel)
{
    Response::closeOutputBuffers($startObLevel + 1, false);
    return ob_get_clean();
} 

如果Response::closeOutputBuffers的第二个参数设置为false,它将在后台调用"ob_end_clean"而不是"ob_eend_flush"。但是,已渲染的内容将丢失。