如何在Symfony 4中使用事件处理异常?

3

现在我正在尝试捕获类似这样的异常事件:

Original Answer翻译成"最初的回答"

try {
    echo 1 / 0;
} catch (\Exception $e){
    $subs = new ExceptionSubscriber();
    $this->dispatcher->addSubscriber($subs);
};

我定义了一个名为ExceptionSubscriber的类,代码如下:

class ExceptionSubscriber implements EventSubscriberInterface
{

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::EXCEPTION => [
                ['processException', 10],
                ['exception', -10],
            ],
        ];
    }

    public function exception(ExceptionEvent $event)
    {
        echo 'test321';
    }

    public function processException(ExceptionEvent $event)
    {
        echo 'test123';
    }
}

And this is my services.yaml

App\EventSubscriber\ExceptionSubscriber:
    tags:
        - { name: kernel.event_subscriber, event: kernel.exception }

我知道我捕获的常规PHP异常不是内核异常事件之一,所以我需要创建自定义异常事件,对吗?
我正在使用EventSubscriber而不是Listener来分派事件,这种方式好吗?
我是否需要分派这些事件,或者它们会以某种神奇的方式传递到订阅者那里?

抱歉,我刚才坐回来发现我已经够了:P 是的,我看到了那些问题,我仍然感到困惑,现在我正在尝试引起内核异常,还不知道如何做,但我在努力。;) - Maarduk
我调用了一个不存在的方法,导致了一个致命错误,我正在思考如何返回除Symfony标准500错误页面以外的其他内容。 - Maarduk
好的,现在我明白了,对我来说入口点是一个控制台,在将内核异常转换为控制台错误后,现在它似乎正在工作! - Maarduk
2个回答

8
当抛出异常(且未处理)时,HttpKernel 会捕获它并分发一个 kernel.exception 事件。
但在您的示例中,这永远不会发生,因为您自己捕获了异常。并尝试创建一个订阅者,这没有多大意义;如果有什么需要,您将分发一个事件。但是,分发新事件并不必要,因为框架已经分发了 kernel.exception 事件。
如果您想捕获该事件,则需要创建自己的事件侦听器。下面是一个基本示例:
class ExceptionListener
{
    public function onKernelException(ExceptionEvent $event)
    {
        $exception = $event->getException();

        // inspect the exception
        // do whatever else you want, logging, modify the response, etc, etc
    }
}

您需要配置此类以侦听这些事件:
services:
    App\EventListener\ExceptionListener:
        tags:
            - { name: kernel.event_listener, event: kernel.exception }

没有其他需要做的事情了。任何未捕获的异常都会经过这里。不需要创建特定的try/catch块(尽管通常情况下,处理自己的异常是一件好事)。

这些地方的文档中都有详细解释:


订阅者比监听器更好:无需编写配置,直接在代码中订阅事件... - Florian Hermann
这主要是个人喜好的问题。就我个人而言,我更喜欢明确配置监听器并且每个监听器只处理单一任务。 - yivi
我猜是的。我不应该那么严格。也许这篇文章可以改变你的想法 :p https://www.tomasvotruba.cz/blog/2019/05/16/don-t-ever-use-listeners/ - Florian Hermann
我已经熟悉那篇文章了。恰巧,我不同意它提出的许多观点。 - yivi

1
控制器中未捕获的异常被Symfony捕获,然后构造和分派内核异常事件。
实际上,您没有捕获任何异常,而是订阅了一个事件。Symfony会捕获它们,您将收到一个带有方法getException的事件。
您可以在此处找到更多信息:Symfony: 如何自定义错误页面

好的,我订阅了自动分派的事件,在内核中通过添加 $container->register('subscriber_service_id', ExceptionSubscriber::class)->addTag('kernel.event_subscriber'); 来实现。 - Maarduk
我该怎么做才能捕获一个来自服务的异常? - Maarduk
@Maarduk Symfony仍然是PHP,要捕获异常只需使用常规的try-catch块, 只有当没有显式地捕获异常时,Symfony才会捕获它,然后分派事件。对于配置,它取决于您的环境。如果您正在使用框架包并启用了自动装配,则Symfony将自动获取实现EventSubscriberInterface的任何服务,并将其注册为订阅者。如果没有自动装配,则必须手动标记它。 - Code Spirit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接