三沣开发知识 购物 网址 游戏 小说 歌词 地图 快照 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 开发 租车 短信 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题
autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml
html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> PHP -> Symfony2源码分析——启动过程2 -> 正文阅读
 

[PHP]Symfony2源码分析——启动过程2

Symfony2源码分析——启动过程2   文章地址:http://www.hcoding.com/?p=46
  上一篇分析Symfony2框架源码,探究Symfony2如何完成一个请求的前半部分,前半部分可以理解为Symfony2框架为处理请求做准备工作,包括container生成、缓存、bundls初始化等一些列准备工作(Symfony2源码分析——启动过程1)。而这一篇讲的是Symfony2如何根据请求的数据生成Response对象,向客户端返回响应数据。
  在分析前需要了解Symfony2的事件驱动机制:Symfony2事件驱动。
  言归正传,Symfony2请求的工作流程其实是Symfony2内核的事件驱动完成的,下面是Symfony2框架定义好的内核事件:


final class KernelEvents
{
    /**
     * The REQUEST event occurs at the very beginning of request
     * dispatching
     *
     * This event allows you to create a response for a request before any
     * other code in the framework is executed. The event listener method
     * receives a Symfony\Component\HttpKernel\Event\GetResponseEvent
     * instance.
     *
     * @var string
     *
     * @api
     */
    const REQUEST = 'kernel.request';

    /**
     * The EXCEPTION event occurs when an uncaught exception appears
     *
     * This event allows you to create a response for a thrown exception or
     * to modify the thrown exception. The event listener method receives
     * a Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent
     * instance.
     *
     * @var string
     *
     * @api
     */
    const EXCEPTION = 'kernel.exception';

    /**
     * The VIEW event occurs when the return value of a controller
     * is not a Response instance
     *
     * This event allows you to create a response for the return value of the
     * controller. The event listener method receives a
     * Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent
     * instance.
     *
     * @var string
     *
     * @api
     */
    const VIEW = 'kernel.view';

    /**
     * The CONTROLLER event occurs once a controller was found for
     * handling a request
     *
     * This event allows you to change the controller that will handle the
     * request. The event listener method receives a
     * Symfony\Component\HttpKernel\Event\FilterControllerEvent instance.
     *
     * @var string
     *
     * @api
     */
    const CONTROLLER = 'kernel.controller';

    /**
     * The RESPONSE event occurs once a response was created for
     * replying to a request
     *
     * This event allows you to modify or replace the response that will be
     * replied. The event listener method receives a
     * Symfony\Component\HttpKernel\Event\FilterResponseEvent instance.
     *
     * @var string
     *
     * @api
     */
    const RESPONSE = 'kernel.response';

    /**
     * The TERMINATE event occurs once a response was sent
     *
     * This event allows you to run expensive post-response jobs.
     * The event listener method receives a
     * Symfony\Component\HttpKernel\Event\PostResponseEvent instance.
     *
     * @var string
     */
    const TERMINATE = 'kernel.terminate';

    /**
     * The FINISH_REQUEST event occurs when a response was generated for a request.
     *
     * This event allows you to reset the global and environmental state of
     * the application, when it was changed during the request.
     *
     * @var string
     */
    const FINISH_REQUEST = 'kernel.finish_request';
}

View Code
  我们可以编写事件监听器,监听相应的内核事件,在Symfony2触发该事件的时候,相应的事件监听器就会执行。监听和唤醒形象的描述,就像,你(事件监听器)参加校运会,去大会(Symfony2)登记(监听)参加50米短跑(事件),当50米短跑比赛开始了(事件被触发),那你就奔跑吧(监听器执行,其实就是一个执行函数,函数完成什么工作就取决于你的需求了),少年。
  Symfony2的内核事件处理流程大部分工作都在HttpKernel::handleRaw方法中:

 1     private function handleRaw(Request $request, $type = self::MASTER_REQUEST)
 2     {
 3         $this->requestStack->push($request);
 4 
 5         // request
 6         // 初始化事件,事件对象会被传递给监听器,所以事件可以说是一个信息的载体,事件内存放着监听器感兴趣的数据。
 7         $event = new GetResponseEvent($this, $request, $type);
 8         // 触发kernel.request事件,后续详细讲解EventDispatcher::dispatch方法的实现,
 9         // 这里我们需要知道的是,dispatcher把$event传递给所有监听了kernel.request事件的监听器,监听器将会执行。
10         // kernel.request事件发生在controller执行之前,我们可以在这一步奏完成路由解析等为controller执行提供准备数据,
11         // 在这个过程允许我们直接生成Response对象,向客户端输出数据,那么controller就不会被执行了。
12         $this->dispatcher->dispatch(KernelEvents::REQUEST, $event);
13 
14         // 如果我们在kernel.request事件生成了Response对象(响应数据),那么就跳过kernel.controller、kernel.view事件、
15         // controller也会被跳过,直接执行kernel.response事件。
16         if ($event->hasResponse()) {
17             return $this->filterResponse($event->getResponse(), $request, $type);
18         }
19 
20         // load controller
21         // 根据路由规则返回 一个对象或者数组或者字符串 ,如果$controller是一个数组,$controller[0]是存放的是要执行的controller对象,
22         // $controller[0]存放的是controller对象执行的方法,即action,方法的参数没有保存在$controller数组中;
23         // 如果$controller是对象,那么该对象就实现了__invoke 方法;
24         // 如果$controller是字符串,那么$controller就是要运行的函数的函数名。
25         // 图2是$controller的一个var_dump例子
26         if (false === $controller = $this->resolver->getController($request)) {
27             throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". Maybe you forgot to add the matching route in your routing configuration?', $request->getPathInfo()));
28         }
29 
30         $event = new FilterControllerEvent($this, $controller, $request, $type);
31         // 触发kernel.controller事件,这个事件发生在controller执行前。我们可以通过监听这个事件在controller执行前修改controller,
32         // 或者完成一些动作。
33         $this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event);
34         $controller = $event->getController();
35 
36         // controller arguments
37         // 从request对象中获取controller方法的参数
38         $arguments = $this->resolver->getArguments($request, $controller);
39 
40         // call controller
41         // 执行controller
42         $response = call_user_func_array($controller, $arguments);
43 
44         // view
45         // 如果$response不是Response对象,那么kernel.view事件就会触发,监听kernel.view事件的监听器通过$response值生成Response对象。
46         if (!$response instanceof Response) {
47             $event = new GetResponseForControllerResultEvent($this, $request, $type, $response);
48             $this->dispatcher->dispatch(KernelEvents::VIEW, $event);
49 
50             if ($event->hasResponse()) {
51                 $response = $event->getResponse();
52             }
53 
54             if (!$response instanceof Response) {
55                 $msg = sprintf('The controller must return a response (%s given).', $this->varToString($response));
56 
57                 // the user may have forgotten to return something
58                 if (null === $response) {
59                     $msg .= ' Did you forget to add a return statement somewhere in your controller?';
60                 }
61                 throw new \LogicException($msg);
62             }
63         }
64 
65         // 触发kernel.response事件,在向客户端输出Response对象前,我们可以对Response对象进行修改,
66         // 例如修改response头部,设置缓存、压缩输出数据等。
67 
68         // 接着触发kernel.finish_request事件,把当前请求从请求栈中弹出,当前请求就完成。
69         return $this->filterResponse($response, $request, $type);
70 
71         // 千万别忘记了,filterResponse执行完后,Symfony2内核事件处理流程还有最后一步,位于app_dev.php[app.php]最后一行,
72         // $kernel->terminate($request, $response);这个方法触发kernel.terminate事件,此时,Symfony2已经响应了客户端的请求,
73         // 向客户端输出了Response对象。监听kernel.terminate事件的监听器,主要是为了完成一些耗时的操作,操作的结果不需要返回给
74         // 客户端的,例如邮件发送、图片压缩等等。
75         // 到这里,Symfony2的整个流程就走完了。
76     }


HttpKernel::filterResponse方法和HttpKernel::finishRequest方法:



 1     private function filterResponse(Response $response, Request $request, $type)
 2     {
 3         $event = new FilterResponseEvent($this, $request, $type, $response);
 4 
 5         $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event);
 6 
 7         $this->finishRequest($request, $type);
 8 
 9         return $event->getResponse();
10     }
11 
12     /**
13      * Publishes the finish request event, then pop the request from the stack.
14      *
15      * Note that the order of the operations is important here, otherwise
16      * operations such as {@link RequestStack::getParentRequest()} can lead to
17      * weird results.
18      *
19      * @param Request $request
20      * @param int     $type
21      */
22     private function finishRequest(Request $request, $type)
23     {
24         $this->dispatcher->dispatch(KernelEvents::FINISH_REQUEST, new FinishRequestEvent($this, $request, $type));
25         $this->requestStack->pop();
26     }

View Code

图2
Symfony2框架的事件分发机制的核心代码:

 1     public function dispatch($eventName, Event $event = null)
 2     {
 3         if (null === $event) {
 4             $event = new Event();
 5         }
 6 
 7         $event->setDispatcher($this);
 8         $event->setName($eventName);
 9 
10         if (!isset($this->listeners[$eventName])) {
11             return $event;
12         }
13 
14         // $eventName即:KernelEvents::REQUEST、KernelEvents::CONTROLLER、KernelEvents::VIEW、KernelEvents::RESPONSE、KernelEvents::TERMINATE等
15         // getListeners返回所有监听$eventName事件的监听器
16         $this->doDispatch($this->getListeners($eventName), $eventName, $event);
17 
18         return $event;
19     }
20 
21     protected function doDispatch($listeners, $eventName, Event $event)
22     {
23         // 监听器执行
24         foreach ($listeners as $listener) {
25             call_user_func($listener, $event, $eventName, $this);
26             // 如果其中一个监听器把$event的propagationStopped属性设置为true,那么表示$eventName这一事件终止执行,
27             // 事件不会往$listeners里尚未执行的监听器传递该事件。
28             if ($event->isPropagationStopped()) {
29                 break;
30             }
31         }
32     }

  PHP 最新文章
PHP中被忽略的性能优化利器:生成器
cakephp搭建配置完成后怎么关闭cake标识
如何配置php session使用redis集群
cakephp怎么默认显示index/index文件
PHP入门怎么选?大学生适合学习吗?
php 回调函数和匿名函数
工厂模式
PHP安装、配置及拓展总结
谈谈php中上传文件的处理
【PHP开发】国外程序员收集整理的 PHP 资源
上一篇文章      下一篇文章      查看所有文章
加:2015-03-30 02:23:50  更:2017-05-15 14:24:45 
 
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2017年12日历
2017-12-17 18:04:03
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库