php - 在 Zend Framework 3 中捕获异常
问题描述
我使用 ZF3 骨架应用程序。我想知道我应该在哪里全局捕获异常。
示例:现在,如果我访问无效路由 (mysite.com/invalid-route),应用程序会报告未捕获的期望和 HTTP 响应代码 200
致命错误:未捕获 Zend\View\Exception\RuntimeException:未提供 RouteMatch 实例
我希望触发内置的 404 错误页面。
我错过了什么?有人可以指出我正确的方向吗?
使用以下代码正确记录异常:
class Module implements ConfigProviderInterface
{
const VERSION = '3.0.3-dev';
public function onBootstrap()
{
$logger = new Logger();
$writer = new Writer\Stream(__DIR__ . '/../../../data/log/error.log');
$logger->addWriter($writer);
// Log PHP errors
Logger::registerErrorHandler($logger, true);
// Log exceptions
Logger::registerExceptionHandler($logger);
}
解决方案
这是您可以使用侦听器捕获的东西,在 early event 上触发MvcEvent::EVENT_ROUTE
。
我建议使用专门的类和工厂来分离对onBootstrap
函数使用的关注。您可以通过注册和“激活”一个 Listener 类来做到这一点,如下所示:
'listeners' => [
// This makes sure it "gets listened to" from the very start of the application (onBootstrap)
RouteExistsListener::class,
],
'service_manager' => [
'factories' => [
// This is just what you think it is
RouteExistsListener::class => InvokableFactory::class,
],
],
你可以只使用InvokableFactory
这个监听器,因为没有特殊要求。
class RouteExistsListener implements ListenerAggregateInterface
{
/**
* @var array
*/
protected $listeners = [];
/**
* @param EventManagerInterface $events
*/
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
/**
* @param EventManagerInterface $events
*/
public function attach(EventManagerInterface $events, $priority = 1)
{
$events->attach(MvcEvent::EVENT_ROUTE, [$this, 'doesRouteExist'], 100);
}
/**
* @param MvcEvent $event
*
* @return void|Response
* @throws Exception
*/
public function doesRouteExist(MvcEvent $event)
{
/** @var TranslatorAwareTreeRouteStack|TreeRouteStack $router */
$router = $event->getRouter();
/** @var Request $request */
$request = $event->getRequest();
/** @var RouteMatch|null $routeExists */
$routeExists = $router->match($request); // Return RouteMatch|null
if ($routeExists instanceof RouteMatch) {
return; // Route exists - nothing to do
}
$url = $router->assemble([], ['name' => 'home']); // Name of your redirect route (ie. not_found/404, or something)
/** @var Response $response */
$response = $event->getResponse();
$response->getHeaders()->addHeaderLine('Location', $url);
$response->setStatusCode(302);
$response->sendHeaders();
$event->getApplication()->getEventManager()->attach(
MvcEvent::EVENT_ROUTE,
function (MvcEvent $event) use ($response) {
$event->stopPropagation();
return $response;
},
-10000
);
return $response;
}
}
注意:为上述内容使用了我自己的现有类,并按照我认为应该可以使用的方式进行了修改。但是,可能包含一两个错误;-) 不过,我认为应该为您指明正确的方向。
推荐阅读
- github - 如何在 Github 的个人资料上显示 readme.md 文件?
- c++ - ARM7 交叉编译:elf 文件中缺少符号
- php - PhpStorm Docker & 零配置 Xdebug
- r - shinjs::show() 在 shinyjs::hide() 之后不显示元素
- python - 使用 Pandas 连接两个数据框
- flutter - 上下文在 Flutter 中的 Navigator.pushReplacement 中显示错误
- java - 对在 for 循环中获取多个字符串感到困惑
- ember.js - EmberJs:如何将数据动态注入 ENV?
- android-studio - 覆盖服务中的 getClipboard 内容不适用于新的 Android 版本。选择?
- angular - Angular,如何在服务变量上创建间谍对象