Action Helpers是否有钩子自动运行,抛出异常与否?

时间:2010-11-02 10:01:38

标签: zend-framework

已更新

想要使用每个控制器运行一些代码,并且told使用Action Helpers或插件而不是从基本控制器扩展,我决定使用Action Helper而不是Plugin,每个优秀的幻灯片都是{{ 3}}(Ryan Mauger);

Zend Framework,开始掌握: @Bittarman 见幻灯片22: (动作助手)前/后派遣中的抛出异常将停止进一步执行......

虽然它已停止进一步执行,但未捕获异常。我一直试图调试这几个小时,但没有到达任何地方。

如果您运行以下代码,您是否看到异常被捕获或是否从错误控制器中逃脱?

我正在试图弄清楚Zend Framework是否表现不如预期,或者我是否完全搞砸了(更有可能)。

我试图将其分解为最简单的情况来复制,让我知道你看到了什么:

/ *添加到此处的现有Bootstrap:APPLICATION_PATH / Bootstrap.php * /

protected function _initActionHelpers()
{
    Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH .'/controllers/helpers');
    //hooks cause action helper to autorun: http://akrabat.com/zend-framework/hooks-in-action-helpers/
    $hooks = Zend_Controller_Action_HelperBroker::getStaticHelper('Test');
    Zend_Controller_Action_HelperBroker::addHelper($hooks);
}

/ * in:APPLICATION_PATH / controllers / helpers / Test.php * /

<?php
class Zend_Controller_Action_Helper_Test extends Zend_Controller_Action_Helper_Abstract
{

    public function preDispatch()
    {
        // you can skip next line if you don't have xdebug
        //xdebug_disable();
        throw new Exception('test', 404);
        parent::preDispatch();
    }
}

更新 好吧,我一直在通过xDebug + Eclipse运行这个...(或者是那个或者玩得很开心,不确定我是否选择了更愉快的体验)....我发现了一些奇怪的东西。 / p>

preDispatch正在运行两次! 在第二次调用时,它转到Zend_Controller_Plugin / ErrorHandler.php 运行此代码的地方:

if ($this->_isInsideErrorHandlerLoop) {
    $exceptions = $response->getException();
    if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) {
        // Exception thrown by error handler; tell the front controller to throw it
        $frontController->throwExceptions(true);
        throw array_pop($exceptions);
    }
}

通过将throw Exceptions设置为true,它不再被捕获。我怀疑这是为了避免发生循环($ this-&gt; _isInsideErrorHandlerLoop也是一个微妙的线索;)

为什么它在循环中?

2 个答案:

答案 0 :(得分:5)

好的,@ Bittarman在IRC的#ZFTalk上给了我答案。在这里(并且道歉,我将自己的答案标记为正确..但我不想让他更多地将其写在这里以便将其写下来。)

if( ($this->getRequest()->getActionName() == 'error') && ($this->getRequest()->getControllerName() == 'error')) {
    return;
}

原因是错误处理程序必须自行禁用 (通过将throw异常设置为true)当它出现错误时 处理程序循环所以你有了 确保错误控制器中没有发生异常情况。

答案 1 :(得分:3)

ErrorHandler插件旨在捕获mvc组件抛出的异常,而不是插件。它挂钩到postDispatch并检查调度的异常 - 而不是其他任何东西。 它不会像preDispatch那样在此之前捕获异常。

如果查看ErrorHandler插件的源代码,可以看到它检查Request对象中的Exceptions。这仅在frontController选项'throwExceptions'设置为false时才有效,这使得他可以捕获异常并将其存储起来供以后使用(如插件处理程序)。

在您的情况下,异常未被前控制器捕获,因此被抛到应用程序的最顶端。您确定可以编辑frontController以在发送之前捕获异常 - 但这并非故意实现:发送之前的所有内容都可以被视为“引导”应用程序:任何异常都是关键的。就像在真正启动时一样,任何异常都会阻止应用程序运行。所以你真的应该避免任何例外。

更新:好的,这是针对插件部分的,忘了你想知道ActionHelper部分。这些不是由FrontController执行的,而是由Zend_Controller_Action执行的。因为它们是调度的一部分,由FrontController捕获并由ErrorHandler插件处理。
但是ErrorHandler做了什么?它使用您的errorController向FrontController添加了另一个请求。所以另一个调度循环完成,你的actionhelper再次抛出异常。由于errorController请求与任何其他请求没有区别,因此ErrorHandler插件会再次捕获它并链接errorController的另一个请求。再次......我想你可以看到这将导致 - 循环。为了防止这种情况,有一个属性可以查看某处是否存在异常。这是为了捕获错误处理程序抛出的任何异常。如果ErrorHandler插件注意到这样的异常,它会将throwException属性覆盖为true并抛出异常。
因此,您可以看到的未处理异常是errorController请求引发的异常。

我可以看到ActionHelpers可以抛出一个异常 - 但你应该非常小心这个原因;)