EventDispatcher组件
编辑该页面EventDispatcher组件
我们的框架是失踪的一个重要特点任何好的框架:可扩展性。可扩展意味着开发人员应该能够钩到框架生命周期修改请求处理的方式。
我们谈论什么样的钩子?身份验证或缓存实例。灵活,钩子必须即插即用;你“注册”的应用程序不同于下一个根据您的具体需求。很多软件都有类似的概念如Drupal或WordPress。在一些语言中,甚至有一个标准WSGI在Python中或架在Ruby中。
作为PHP没有标准,我们将使用著名的设计模式中介,允许任何类型的行为附加到我们的框架;Symfob娱乐下载ony的EventDispatcher组件实现了一个轻量级版本的模式:
1
美元作曲家需要symfony /事件分ob娱乐下载配器
它是如何工作的呢?的调度程序事件调度器的中心对象系统,通知听众一个事件派遣。换句话说:你的代码分派事件分配器,分配器通知所有注册事件侦听器,并且每个事件侦听器为所欲为。
作为一个例子,让我们创建一个监听器,透明地将谷歌分析代码添加到所有的反应。
使它工作,框架必须派遣一个事件之前返回响应实例:
1 2 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 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娱乐下载\组件\EventDispatcher\EventDispatcher;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\HttpFoundation\响应;使用ob娱乐下载\组件\HttpKernel\控制器\ArgumentResolverInterface;使用ob娱乐下载\组件\HttpKernel\控制器\ControllerResolverInterface;使用ob娱乐下载\组件\路由\异常\ResourceNotFoundException;使用ob娱乐下载\组件\路由\匹配器\UrlMatcherInterface;类框架{私人美元调度程序;私人美元匹配器;私人美元controllerResolver;私人美元argumentResolver;公共函数__construct(EventDispatcher美元调度程序,UrlMatcherInterface美元匹配器,ControllerResolverInterface美元controllerResolver,ArgumentResolverInterface美元argumentResolver){美元这- >调度程序=美元调度程序;美元这- >匹配器=美元匹配器;美元这- >controllerResolver =美元controllerResolver;美元这- >argumentResolver =美元argumentResolver;}公共函数处理(请求美元请求){美元这- >匹配器- >getContext ()- >fromRequest (美元请求);试一试{美元请求- >属性- >add (美元这- >匹配器- >匹配(美元请求- >getPathInfo ()));美元控制器=美元这- >controllerResolver- >getController (美元请求);美元参数=美元这- >argumentResolver- >getArguments (美元请求,美元控制器);美元响应=中的call_user_func_array (美元控制器,美元参数);}抓(ResourceNotFoundException美元异常){美元响应=新响应(“没有找到”,404年);}抓(\异常美元异常){美元响应=新响应(“出错”,500年);}/ /调度响应事件美元这- >调度程序- >调度(新ResponseEvent (美元响应,美元请求),“响应”);返回美元响应;}}
每次框架处理一个请求,一个ResponseEvent
事件现在派:
1 2 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(){返回美元这- >请求;}}
调度程序的最后一步是创建前端控制器和注册一个侦听器响应
事件:
1 2 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娱乐下载\组件\EventDispatcher\EventDispatcher;美元调度程序=新EventDispatcher ();美元调度程序- >addListener (“响应”,函数(单纯形\ ResponseEvent美元事件){美元响应=美元事件- >getResponse ();如果(美元响应- >isRedirection () | | (美元响应- >头- >有(“内容类型”)& &假= = =(大小写敏感美元响应- >头- >get (“内容类型”),“html”)| |“html”= = !美元事件- >getRequest ()- >getRequestFormat ()) {返回;}美元响应- >setContent (美元响应- >getContent ()。“GA代码”);});美元controllerResolver=新ControllerResolver ();美元argumentResolver=新ArgumentResolver ();美元框架=新单纯形\框架(美元调度程序,美元匹配器,美元controllerResolver,美元argumentResolver);美元响应=美元框架- >处理(美元请求);美元响应- >send ();
请注意
侦听器只是一个概念验证,你应该添加谷歌分析代码之前body标签。
正如您可以看到的,addListener ()
同事一个有效的PHP命名事件回调(响应
);事件名称必须相同的使用调度()
调用。
在侦听器中,我们添加了谷歌分析代码只有在反应不是一个重定向,如果请求的格式是HTML和响应内容类型的HTML(这些条件展示易于操作请求和响应数据从您的代码)。
到目前还好,但是让我们添加一个侦听器在相同的事件。假设我们想要设置内容长度
的响应如果尚未设置:
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年);
提示
当创建你的框架,考虑优先级(例如储备一些数字为内部的听众)和文档他们彻底。
让我们重构代码有点通过移动谷歌侦听器自身的类:
1 2 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代码”);}}
与其他听众:做同样的
1 2 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
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/ / example.com/src/Simplex/GoogleListener.php名称空间单纯形;使用ob娱乐下载\组件\EventDispatcher\EventSubscriberInterface;类GoogleListener实现了EventSubscriberInterface{/ /……公共静态函数getSubscribedEvents(){返回(“响应”= >“onResponse”];}}
这是新版本的ContentLengthListener
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/ / example.com/src/Simplex/ContentLengthListener.php名称空间单纯形;使用ob娱乐下载\组件\EventDispatcher\EventSubscriberInterface;类ContentLengthListener实现了EventSubscriberInterface{/ /……公共静态函数getSubscribedEvents(){返回(“响应”= > [“onResponse”,-255年]];}}
提示
一个用户可以在主机上尽可能多的听众需要尽可能多的活动。
让你真正灵活的框架,不要犹豫地添加更多的事件;和使它更棒的框,添加更多的听众。同样,这本书不仅仅是创建一个通用框架,但一个适合您的需要。停止每当你认为合适的地方,并进一步发展的代码。