已更新
想要使用每个控制器运行一些代码,并且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也是一个微妙的线索;)
为什么它在循环中?
答案 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可以抛出一个异常 - 但你应该非常小心这个原因;)