从上一篇我们就大概就知道过滤器的定义和怎样去配置,这一节来说说执行流程 

  1. public function run($handlerAdapter = null) {
  2. $handlerAdapter !== null && $this->handlerAdapter = $handlerAdapter;
  3. $module = $this->getModules();
  4. $handlerPath = $module['controller-path'] . '.' . ucfirst($this->handlerAdapter->getController()) . $module['controller-suffix'];
  5. $className = Wind::import($handlerPath);
  6. if (!class_exists($className)) throw new WindException(
  7. 'Your requested \'' . $handlerPath . '\' was not found on this server.', 404);
  8. $handler = new $className();
  9. $handler->setDelayAttributes(
  10. array('errorMessage' => array('ref' => 'errorMessage'), 'forward' => array('ref' => 'forward')));
  11.  
  12. $handlerAdapter !== null && $this->resolveActionFilters($handler);
  13.  
  14. try {
  15. $forward = $handler->doAction($this->handlerAdapter);
  16. $this->doDispatch($forward);
  17. } catch (WindForwardException $e) {
  18. $this->doDispatch($e->getForward());
  19. } catch (WindActionException $e) {
  20. $this->sendErrorMessage(($e->getError() ? $e->getError() : $e->getMessage()), $e->getCode());
  21. } catch (WindException $e) {
  22. $this->sendErrorMessage($e->getMessage(), $e->getCode());
  23. }
  24. }

  要注意的是 handleAdapter这个属性,这个变量到底里面装的是什么呢

我们在控制台看一下把

我这里解释一下把,这里的this是windClassProxy的实例,还记得它是怎样创建的吗,再贴一下这个代码

  1. /**
  2. * 解析action过滤链的配置信息
  3. *
  4. * @param WindSimpleController $handler
  5. * @return void
  6. */
  7. protected function resolveActionFilters(&$handler) {
  8. if (!$filters = $this->getConfig('filters')) return;
  9. /* @var $cache AbstractWindCache */
  10. $_filters = array();
  11. if ($cache = Wind::getComponent('windCache')) {
  12. $_filters = $cache->get('filters');
  13. }
  14. $_token = $this->handlerAdapter->getModule() . '/' . $this->handlerAdapter->getController() . '/' . $this->handlerAdapter->getAction();
  15. if (!isset($_filters[$_token])) {
  16. foreach ($filters as $_filter) {
  17. if (empty($_filter['class'])) continue;
  18. $_pattern = empty($_filter['pattern']) ? '' : $_filter['pattern'];
  19. unset($_filter['pattern']);
  20. if ($_pattern) {
  21. $_pattern = str_replace(array('*', '/'), array('\w*', '\/'), $_pattern);
  22. if (in_array($_pattern[0], array('~', '!'))) {
  23. $_pattern = substr($_pattern, 1);
  24. if (preg_match('/^' . $_pattern . '$/i', $_token)) continue;
  25. } else {
  26. if (!preg_match('/^' . $_pattern . '$/i', $_token)) continue;
  27. }
  28. }
  29. $_filters[$_token][] = $_filter;
  30. }
  31. $cache && $cache->set('filters', $_filters);
  32. }
  33. if (empty($_filters[$_token])) return;
  34. /* @var $proxy WindClassProxy */
  35. $proxy = WindFactory::createInstance(Wind::import('WIND:filter.proxy.WindClassProxy'));
  36. $proxy->registerTargetObject($handler);
  37. foreach ($_filters[$_token] as $value) {
  38. $proxy->registerEventListener(
  39. $this->factory->createInstance(Wind::import($value['class']),
  40. array($handler->getForward(), $handler->getErrorMessage(), $this->handlerAdapter, $value)),
  41. 'doAction');
  42. }
  43. $handler = $proxy;
  44. }

  

关键是这里 

  1. $proxy = WindFactory::createInstance(Wind::import('WIND:filter.proxy.WindClassProxy'));
  2. $proxy->registerTargetObject($handler);
  3. foreach ($_filters[$_token] as $value) {
  4. $proxy->registerEventListener(
  5. $this->factory->createInstance(Wind::import($value['class']),
  6. array($handler->getForward(), $handler->getErrorMessage(), $this->handlerAdapter, $value)),
  7. 'doAction');
  8. }

  创建一个代理类,然后帮定一个事件,把过滤器作为事件处理其实例化然后等下触发,不知道为什么要这样做,想得不是很明白

好啦,万事俱备,只欠东风拉,看看它是这样运作拉

  1. try {
  2. $forward = $handler->doAction($this->handlerAdapter);
  3. $this->doDispatch($forward);
  4. } catch (WindForwardException $e) {
  5. $this->doDispatch($e->getForward());
  6. } catch (WindActionException $e) {
  7. $this->sendErrorMessage(($e->getError() ? $e->getError() : $e->getMessage()), $e->getCode());
  8. } catch (WindException $e) {
  9. $this->sendErrorMessage($e->getMessage(), $e->getCode());
  10. }

  这里会调用doAction这个方法,但是这个方法在windProxyClass根本找不到的,所以会调用php的魔术方法拉,如下

  1. public function __call($methodName, $args) {
  2. $listeners = isset($this->_listener[$methodName]) ? $this->_listener[$methodName] : array();
  3. if (empty($listeners)) return call_user_func_array(array($this->_instance, $methodName), $args);
  4. $interceptorChain = $this->_getInterceptorChain($methodName);
  5. $interceptorChain->addInterceptors($listeners);
  6. $interceptorChain->setCallBack(array($this->_getInstance(), $methodName), $args);
  7. return call_user_func_array(array($interceptorChain->getHandler(), 'handle'), (array) $args);
  8. }

 好啦,高潮来啦,首先要确定一下这个方法有没有绑定一堆的listener,如果没有,就直接地调用算啦,如果有的话,就加入到链条里

这里很有技巧性,看看

  1. * 拦截器的执行入口
  2. *
  3. * @param mixed $var=.. 该接口接受任意参数,并将依次传递给拦截器的前置和后置操作
  4. * @return mixed 返回拦截链执行的最终结果
  5. */
  6. public function handle() {
  7. $args = func_get_args();
  8. $this->result = call_user_func_array(array($this, 'preHandle'), $args);
  9. if ($this->result !== null) {
  10. return $this->result;
  11. }
  12. if (null !== ($handler = $this->interceptorChain->getHandler())) {
  13. $this->result = call_user_func_array(array($handler, 'handle'), $args); //执行过滤器的handle方法
  14. } else {
  15. $this->result = call_user_func_array(array($this->interceptorChain, 'handle'), $args); //如果返回的handle为空的话就执行过滤链的handle的方法,也就是callback,调用控制器阿 
  16. }
  17. call_user_func_array(array($this, 'postHandle'), $args);
  18. return $this->result;
  19. }

  

  1. /**
  2. * 返回拦截链中的下一个拦截器
  3. *
  4. * @return WindHandlerInterceptor
  5. */
  6. public function getHandler() {
  7. if (count($this->_interceptors) <= 1) {
  8. return $this;
  9. }
  10. $handler = next($this->_interceptors);
  11. if ($handler === false) {
  12. reset($this->_interceptors);
  13. return null;
  14. }
  15. if (method_exists($handler, 'handle')) {
  16. $handler->setHandlerInterceptorChain($this); //这里设置有什么用呢,就死为了最后一个调用过滤链的handle方法
  17. return $handler;
  18. }
  19. return $this->getHandler();
  20. }

  

  1. /**
  2. * 执行callback方法
  3. *
  4. * @return mixed $var=.. 如果callBack没有被设置则返回null,否则返回回调函数的结果
  5. * @throws WindException 如果回调函数调用失败则抛出异常
  6. */
  7. public function handle() {
  8. reset($this->_interceptors);
  9. if ($this->_callBack === null) return null;
  10. if (is_string($this->_callBack) && !function_exists($this->_callBack)) {
  11. throw new WindException('[filter.WindHandlerInterceptorChain.handle] ' . $this->_callBack,
  12. WindException::ERROR_FUNCTION_NOT_EXIST);
  13. }
  14. $this->_args || $this->_args = func_get_args();
  15. return call_user_func_array($this->_callBack, (array) $this->_args);
  16. }

  这个是最后执行的,过滤器一个一个执行完了,就执行callback拉 ,有时间画一个图出来会比较容易理解拉 

捣蛋phpwind过滤器执行流程的更多相关文章

  1. 捣蛋phpwind之WindFrameWork

    一直都有关注phpwind这个开源产品,从9.0开始就好关注拉,因为官方说把之前的代码重写了一遍,融入了windFramework这个框架,代码真的挺优美的,今日在做社区的一些功能,心血来潮就参考了p ...

  2. 轻量级前端MVVM框架avalon - 执行流程2

    接上一章 执行流程1 在这一大堆扫描绑定方法中应该会哪些实现? 首先我们看avalon能帮你做什么? 数据填充,比如表单的一些初始值,切换卡的各个面板的内容({{xxx}},{{xxx|html}}, ...

  3. ThinkPHP2.2框架执行流程图,ThinkPHP控制器的执行流程

    ThinkPHP2.2框架执行原理.流程图在线手册 ThinkPHP控制器的执行流程 对用户的第一次URL访问 http://<serverIp>/My/index.php/Index/s ...

  4. Servlet、Struts2、SpringMVC执行流程

    Servlet 有以下四个阶段: 1.加载和实例化 Servlet容器负责加载和实例化Servlet. 当Servlet容器启动时,或者在容器检测到需要这个Servlet来响应第一个请求时,创建Ser ...

  5. struts2 之 【struts2简介,struts2开发步骤,struts2详细配置,struts2执行流程】

    入门框架学习避免不了的问题: 1. 什么是框架? 简单的说,框架就是模板,模子,模型.就是一个可重用的半成品. 2. 如何学习框架? 学习框架其实就是学习规则,使用框架就是遵循框架的规则,框架是可变的 ...

  6. Struts框架之 执行流程 struts.xml 配置详细

    1.执行流程 服务器启动: 1. 加载项目web.xml 2. 创建Struts核心过滤器对象, 执行filter  →  init()   struts-default.xml,    核心功能的初 ...

  7. Struts2第二篇【开发步骤、执行流程、struts.xml讲解、defalut-struts讲解】

    前言 我们现在学习的是Struts2,其实Struts1和Struts2在技术上是没有很大的关联的.Struts2其实基于Web Work框架的,只不过它的推广没有Struts1好,因此就拿着Stru ...

  8. Spring Security Oauth2 单点登录案例实现和执行流程剖析

    Spring Security Oauth2 OAuth是一个关于授权的开放网络标准,在全世界得到的广泛的应用,目前是2.0的版本.OAuth2在“客户端”与“服务提供商”之间,设置了一个授权层(au ...

  9. Spring Security 案例实现和执行流程剖析

    Spring Security Spring Security 是 Spring 社区的一个顶级项目,也是 Spring Boot 官方推荐使用的安全框架.除了常规的认证(Authentication ...

随机推荐

  1. 神经网络:卷积神经网络CNN

    一.前言 这篇卷积神经网络是前面介绍的多层神经网络的进一步深入,它将深度学习的思想引入到了神经网络当中,通过卷积运算来由浅入深的提取图像的不同层次的特征,而利用神经网络的训练过程让整个网络自动调节卷积 ...

  2. jenkins的搭建和使用

    Jenkins 是一个开源项目,提供了一种易于使用的持续集成系统,使开发者从繁杂的集成中解脱出来,专注于更为重要的业务逻辑实现上.同时 Jenkins 能实施监控集成中存在的错误,提供详细的日志文件和 ...

  3. 无开发经验,初学python

    1.无开发经验,初学python   如果你不会其他语言,python是你的第一门语言: A Byte of Python (简明python教程,这个有中文版简明 Python 教程)是非常好的入门 ...

  4. Django自定义模型(model)中的字段标签

    方法一: 在编辑页面中,每个字段的标签都是从模块的字段名称生成的. 规则很简单: 用空格替换下划线:首字母大写.例如:Book模块中publication_date的标签是Publication da ...

  5. 《c程序设计语言》读书笔记--反转字符串

    #include "stdio.h" #define Num 100 void reverse(char words[]) { int i, j, c, n=0; while(wo ...

  6. HDU 4752 Polygon(抛物线长度积分)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4752 题意:给出一个抛物线和一个简单多边形.求抛物线在多边形内部的长度. 思路:首先求出多边形所有边和 ...

  7. 《OD大数据实战》Hive环境搭建

    一.搭建hadoop环境 <OD大数据实战>hadoop伪分布式环境搭建 二.Hive环境搭建 1. 准备安装文件 下载地址: http://archive.cloudera.com/cd ...

  8. Android使用 LruCache 缓存图片

    摘要:在你应用程序的UI界面加载一张图片是一件很简单的事情,但是当你需要在界面上加载一大堆图片的时候,情况就变得复杂起来. 使用图片缓存技术 在 你应用程序的UI界面加载一张图片是一件很简单的事情,但 ...

  9. Android 最火的快速开发框架XUtils

    参考:http://www.oschina.net/p/xutils 项目git地址https://github.com/wyouflf/xUtils 目录(?)[-] 最近搜了一些框架供初学者学习比 ...

  10. 【英语】Bingo口语笔记(13) - Call系列

    call off - call it off 取消它 call it a day / call it a night 今天到此结束吧/今晚到此结束吧