手册
目录
收藏793
分享
阅读25465
更新时间2022-04-13
在symfony程序执行期间,大量的事件通知(event notifications)会被触发。你的程序可以监听这些通知,并执行任意代码作为回应。
Symfony自身提供的内部事件,被定义在KernelEvents类中。第三方Bundle和类库也会触发大量事件,你自己的程序可以触发自定义事件。
本文展示的所有例子,考虑到一致性,使用了相同的KernelEvents::EXCEPTION事件。在你自己的程序中,你可以使用任何事件,甚至在同一订阅器中(subscriber)混合若干事件。
监听一个事件最常用的方式是注册一个事件监听(event listener):
// src/AppBundle/EventListener/ExceptionListener.phpnamespace AppBundle\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; class ExceptionListener{
public function onKernelException(GetResponseForExceptionEvent $event)
{
// You get the exception object from the received event
// 你可以从接收到的事件中,取得异常对象
$exception = $event->getException();
$message = sprintf(
'My Error says: %s with code: %s',
$exception->getMessage(),
$exception->getCode()
); // Customize your response object to display the exception details
// 自定义响应对象,来显示异常的细节
$response = new Response();
$response->setContent($message); // HttpExceptionInterface is a special type of exception that
// holds status code and header details
// HttpExceptionInterface是一个特殊类型的异常,持有状态码和头信息的细节
if ($exception instanceof HttpExceptionInterface) {
$response->setStatusCode($exception->getStatusCode());
$response->headers->replace($exception->getHeaders());
} else {
$response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
} // Send the modified response object to the event
// 发送修改后的响应对象到事件中
$event->setResponse($response);
}}每一个事件,都要接收“类型略有不同”的$event对象。对于kernel.exception事件,这个对象是GetResponseForExceptionEvent。要了解每一个“事件监听”所接收到的“事件对象”之类型,参考KernelEvents,或是你要监听的特定事件之文档。
现在,类被创建了,你只需把它注册成服务,然后通过使用一个特殊的“tag”(标签),告诉Symfony这是一个针对kernel.exception事件的“监听”:
YAML:# app/config/services.ymlservices:
app.exception_listener:
class: AppBundle\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }xml:<!-- app/config/services.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="app.exception_listener" class="AppBundle\EventListener\ExceptionListener"> <tag name="kernel.event_listener" event="kernel.exception" /> </service> </services></container>
php:// app/config/services.php$container
->register('app.exception_listener', 'AppBundle\EventListener\ExceptionListener')
->addTag('kernel.event_listener', array('event' => 'kernel.exception'));有一个可选的tag属性是method,它定义了“当事件被触发时,哪个方法要被执行”。默认时,方法的名字是on+“驼峰事件名”。如果事件是kernel.exception的话,默认执行的方法则是onKernelException()。
另有一个可选的tag属性是priority,它的默认值是0,用来控制监听被执行的顺序(一个监听器的优先级愈高则愈早被执行)。这在你要“确保某个监听在其他监听之前被执行”时是有用的。Symfony的内部监听,其优先级范围是-255到255,但你自己的监听可以使用任何正或负的整数。
另一种监听事件的方式是event subscriber事件订阅,它是一个类,定义了一或多个方法,用于监听一或多个事件。同事件监听的主要区别在于,订阅器始终知道它们正在监听的事件是哪一个。
在一个给定的订阅器中,不同的方法可以监听同一个事件。方法被执行时的顺序,通过每一个方法中的priority参数来定义(优先级愈高则方法愈早被调用)。要了解更多关于订阅器的内容,参考EventDispatcher组件。
下例展示了一个事件订阅,定义了若干方法,监听的是同一个kernel.exception事件:
// src/AppBundle/EventSubscriber/ExceptionSubscriber.phpnamespace AppBundle\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;use Symfony\Component\HttpKernel\KernelEvents; class ExceptionSubscriber implements EventSubscriberInterface{
public static function getSubscribedEvents()
{
// return the subscribed events, their methods and priorities
// 返回被订阅的事件,以及它们的方法和属性
return array(
KernelEvents::EXCEPTION => array(
array('processException', 10),
array('logException', 0),
array('notifyException', -10),
)
);
} public function processException(GetResponseForExceptionEvent $event)
{
// ...
} public function logException(GetResponseForExceptionEvent $event)
{
// ...
} public function notifyException(GetResponseForExceptionEvent $event)
{
// ...
}}现在,你只需把这个类注册成服务,并打上kernel.event_subscriber标签,即可告诉Symofny这是一个事件订阅器:
PHP:// app/config/services.php$container
->register(
'app.exception_subscriber',
'AppBundle\EventSubscriber\ExceptionSubscriber'
)
->addTag('kernel.event_subscriber');XML:<!-- app/config/services.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="app.exception_subscriber" class="AppBundle\EventSubscriber\ExceptionSubscriber"> <tag name="kernel.event_subscriber"/> </service> </services></container>
YAML:# app/config/services.ymlservices:
app.exception_subscriber:
class: AppBundle\EventSubscriber\ExceptionSubscriber
tags:
- { name: kernel.event_subscriber }一个单一页面,可以产生若干次请求(一个主请求[master request],然后是多个子请求[sub-requests],典型的像是如何在模板中嵌入控制器)。对于Symfony核心事件,你可能需要检查一下,看这个事件是一个“主”请求还是一个“子”请求:
// src/AppBundle/EventListener/RequestListener.phpnamespace AppBundle\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent;use Symfony\Component\HttpKernel\HttpKernel;use Symfony\Component\HttpKernel\HttpKernelInterface; class RequestListener{
public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
// don't do anything if it's not the master request
// 如果不是主请求,就什么也不做
return;
} // ...
}}特定行为,像是对真正的请求进行检查这种,可能并不需要在子请求的监听中进行。
监听器和订阅器,在同一程序中使用时,可能界限模糊。决定使用哪一种,通常由个人口味决定。但是,每种都有各自的优点:
订阅器易于复用,因为与事件有关的内容存在于类中,而不是存在于服务定义中。这导致Symfony内部使用订阅器;
监听器更灵活,因为bundles可以有条件地开启或关闭它们,基于配置文件中的某些“选项值”。
使用命令行,你可以找到“哪些监听被注册到事件派遣器”。要显示全部事件及其监听,运行:
1 | $ php bin/console debug:event-dispatcher |
通过指定事件名称,你可以得到针对此特定事件进行注册的监听:
1 | $ php bin/console debug:event-dispatcher kernel.exception |
相关
视频
RELATED VIDEOS
科技资讯
1
2
3
4
5
6
7
8
9
精选课程
共5课时
17.2万人学习
共49课时
77万人学习
共29课时
61.7万人学习
共25课时
39.3万人学习
共43课时
70.9万人学习
共25课时
61.6万人学习
共22课时
23万人学习
共28课时
33.9万人学习
共89课时
125万人学习