EventDispatcher组件

编辑本页

警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 5.2,现已不再维护。

本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。

EventDispatcher组件

我们的框架仍然缺少一个好的框架的主要特征:可扩展性.可扩展意味着开发人员应该能够与框架生命周期挂钩,以修改处理请求的方式。

我们说的是什么样的钩子?例如身份验证或缓存。为了灵活,钩子必须是即插即用的;根据您的具体需求,您为应用程序“注册”的对象与下一个对象不同。许多软件都有类似的概念,如Drupal或Wordpress。在一些语言中,甚至有一个标准的likeWSGI使用Python或在Ruby中。

由于PHP没有标准,我们将使用一种众所周知的设计模式中介,允许任何类型的行为附加到我们的框架;Symfob娱乐下载ony EventDispatcher组件实现了这个模式的轻量级版本:

1
作曲家需要symfony/事件调度ob娱乐下载程序

它是如何工作的?的调度程序事件分派器系统的中心对象听众一个事件派出去了。换句话说:代码将事件分派给分派器,分派器通知所有已注册的侦听器该事件,每个侦听器对该事件做任何想做的事情。

例如,让我们创建一个侦听器,透明地将谷歌Analytics代码添加到所有响应中。

为了让它工作,框架必须在返回Response实例之前分派一个事件:

12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/ / example.com/src/Simplex/Framework.php名称空间单纯形使用ob娱乐下载组件EventDispatcherEventDispatcher使用ob娱乐下载组件HttpFoundation请求使用ob娱乐下载组件HttpFoundation响应使用ob娱乐下载组件HttpKernel控制器ArgumentResolverInterface使用ob娱乐下载组件HttpKernel控制器ControllerResolverInterface使用ob娱乐下载组件路由异常ResourceNotFoundException使用ob娱乐下载组件路由匹配器UrlMatcherInterface框架私人调度程序私人匹配器私人controllerResolver私人argumentResolver公共函数__construct(EventDispatcher调度程序, UrlMatcherInterface匹配器, ControllerResolverInterfacecontrollerResolver, ArgumentResolverInterfaceargumentResolver->调度程序=调度程序->匹配器=匹配器->controllerResolver =controllerResolver->argumentResolver =argumentResolver;}公共函数处理(请求请求->匹配器->getContext ()->fromRequest (请求);试一试请求->属性->add (->匹配器->匹配(请求->getPathInfo ()));控制器->controllerResolver->getController (请求);参数->argumentResolver->getArguments (请求控制器);响应=中的call_user_func_array (控制器参数);}(ResourceNotFoundException异常) {响应响应(“没有找到”404);}(\异常异常) {响应响应(“发生错误”500);}//发送一个响应事件->调度程序->调度(ResponseEvent (响应请求),“响应”);返回响应;}}

每当框架处理一个Request时,一个ResponseEvent事件现在被分派:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/ / example.com/src/Simplex/ResponseEvent.php名称空间单纯形使用ob娱乐下载组件HttpFoundation请求使用ob娱乐下载组件HttpFoundation响应使用ob娱乐下载合同EventDispatcher事件ResponseEvent扩展事件私人请求私人响应公共函数__construct(反应响应,请求请求->响应=响应->请求=请求;}公共函数getResponse()返回->反应;}公共函数getRequest()返回->请求;}}

对象的侦听器的注册和调度程序的创建是最后一步响应事件:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/ / example.com/web/front.phprequire_once__DIR__“/ . . /供应商/ autoload.php”/ /……使用ob娱乐下载组件EventDispatcherEventDispatcher调度程序EventDispatcher ();调度程序->addListener (“响应”函数(单纯形\ ResponseEvent事件响应事件->getResponse ();如果响应->isRedirection() ||响应->->有(“内容类型”) & &= = =(大小写敏感响应->->get (“内容类型”),“html”) | |“html”= = !事件->getRequest ()->getRequestFormat()) {返回;}响应->setContent (响应->getContent()。“GA代码”);});controllerResolverControllerResolver ();argumentResolverArgumentResolver ();框架单纯形\框架(调度程序匹配器controllerResolverargumentResolver);响应框架->处理(请求);响应->send ();

请注意

侦听器只是一个概念的证明,您应该在body标记之前添加谷歌Analytics代码。

如你所见,addListener ()将有效的PHP回调关联到命名事件(响应);事件名称必须与调度()调用。

在侦听器中,只有当响应不是重定向、请求格式是HTML且响应内容类型是HTML(这些条件说明了从代码中操作请求和响应数据的容易程度)时,我们才添加谷歌Analytics代码。

到目前为止一切顺利,但是让我们在同一事件上添加另一个侦听器。假设我们想要设置内容长度如果尚未设置,则为:

1 2 3 4 5 6 7 8
调度程序->addListener (“响应”函数(单纯形\ ResponseEvent事件响应事件->getResponse ();响应->头;如果(!->有(内容长度的) && !->有(“传输编码”)) {->集(内容长度的strlen (响应->getContent ()));}});

的值是正确的还是错误的,这取决于您是在上一个侦听器注册之前还是之后添加了这段代码内容长度头。有时,侦听器的顺序很重要,但默认情况下,所有侦听器都以相同的优先级注册,0.要告诉调度程序尽早运行侦听器,请将优先级更改为正数;负数可以用于低优先级的侦听器。这里,我们想要内容长度侦听器最后执行,因此将优先级更改为-255年

1 2 3 4 5 6 7 8
调度程序->addListener (“响应”函数(单纯形\ ResponseEvent事件响应事件->getResponse ();响应->头;如果(!->有(内容长度的) && !->有(“传输编码”)) {->集(内容长度的strlen (响应->getContent ()));}},-255年);

提示

在创建框架时,考虑优先级(例如,为内部侦听器保留一些数字)并彻底记录它们。

让我们通过移动谷歌监听器到它自己的类来重构代码:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/ / example.com/src/Simplex/GoogleListener.php名称空间单纯形GoogleListener公共函数onResponse(ResponseEvent事件响应事件->getResponse ();如果响应->isRedirection() ||响应->->有(“内容类型”) & &= = =(大小写敏感响应->->get (“内容类型”),“html”) | |“html”= = !事件->getRequest ()->getRequestFormat()) {返回;}响应->setContent (响应->getContent()。“GA代码”);}}

对另一个听众做同样的事情:

12 3 4 5 6 7 8 9 10 11 12 13 14 15
/ / example.com/src/Simplex/ContentLengthListener.php名称空间单纯形ContentLengthListener公共函数onResponse(ResponseEvent事件响应事件->getResponse ();响应->头;如果(!->有(内容长度的) && !->有(“传输编码”)) {->集(内容长度的strlen (响应->getContent ()));}}}

我们的前端控制器现在看起来应该如下所示:

1 2 3
调度程序EventDispatcher ();调度程序->addListener (“响应”, (单纯形\ ContentLengthListener (),“onResponse”),-255年);调度程序->addListener (“响应”, (单纯形\ GoogleListener (),“onResponse”]);

即使代码现在很好地包装在类中,仍然存在一个小问题:优先级的知识是“硬编码”在前端控制器中,而不是在侦听器本身中。对于每个应用程序,您必须记住设置适当的优先级。此外,侦听器方法名也暴露在这里,这意味着重构侦听器将意味着更改依赖于这些侦听器的所有应用程序。解决这一困境的方法是使用订阅者而不是监听者:

1 2 3
调度程序EventDispatcher ();调度程序->addSubscriber (单纯形\ ContentLengthListener ());调度程序->addSubscriber (单纯形\ GoogleListener ());

订阅程序知道它感兴趣的所有事件,并将此信息通过getSubscribedEvents ()方法。看看新版本的GoogleListener

12 3 4 5 6 7 8 9 10 11 12 13 14
/ / example.com/src/Simplex/GoogleListener.php名称空间单纯形使用ob娱乐下载组件EventDispatcherEventSubscriberInterfaceGoogleListener实现了EventSubscriberInterface/ /……公共静态函数getSubscribedEvents()返回“响应”= >“onResponse”];}}

这是新版的ContentLengthListener

12 3 4 5 6 7 8 9 10 11 12 13 14
/ / example.com/src/Simplex/ContentLengthListener.php名称空间单纯形使用ob娱乐下载组件EventDispatcherEventSubscriberInterfaceContentLengthListener实现了EventSubscriberInterface/ /……公共静态函数getSubscribedEvents()返回“响应”= > [“onResponse”-255年]];}}

提示

单个订阅者可以在所需的任意事件上托管任意数量的侦听器。

为了使你的框架真正灵活,不要犹豫添加更多的事件;为了让它更棒,添加更多的监听器。同样,这本书不是关于创建一个通用的框架,而是根据您的需要量身定制的框架。在您认为合适的时候停止,并从那里进一步发展代码。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。