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

public function run($handlerAdapter = null) {
$handlerAdapter !== null && $this->handlerAdapter = $handlerAdapter;
$module = $this->getModules();
$handlerPath = $module['controller-path'] . '.' . ucfirst($this->handlerAdapter->getController()) . $module['controller-suffix'];
$className = Wind::import($handlerPath);
if (!class_exists($className)) throw new WindException(
'Your requested \'' . $handlerPath . '\' was not found on this server.', 404);
$handler = new $className();
$handler->setDelayAttributes(
array('errorMessage' => array('ref' => 'errorMessage'), 'forward' => array('ref' => 'forward'))); $handlerAdapter !== null && $this->resolveActionFilters($handler); try {
$forward = $handler->doAction($this->handlerAdapter);
$this->doDispatch($forward);
} catch (WindForwardException $e) {
$this->doDispatch($e->getForward());
} catch (WindActionException $e) {
$this->sendErrorMessage(($e->getError() ? $e->getError() : $e->getMessage()), $e->getCode());
} catch (WindException $e) {
$this->sendErrorMessage($e->getMessage(), $e->getCode());
}
}

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

我们在控制台看一下把

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

/**
* 解析action过滤链的配置信息
*
* @param WindSimpleController $handler
* @return void
*/
protected function resolveActionFilters(&$handler) {
if (!$filters = $this->getConfig('filters')) return;
/* @var $cache AbstractWindCache */
$_filters = array();
if ($cache = Wind::getComponent('windCache')) {
$_filters = $cache->get('filters');
}
$_token = $this->handlerAdapter->getModule() . '/' . $this->handlerAdapter->getController() . '/' . $this->handlerAdapter->getAction();
if (!isset($_filters[$_token])) {
foreach ($filters as $_filter) {
if (empty($_filter['class'])) continue;
$_pattern = empty($_filter['pattern']) ? '' : $_filter['pattern'];
unset($_filter['pattern']);
if ($_pattern) {
$_pattern = str_replace(array('*', '/'), array('\w*', '\/'), $_pattern);
if (in_array($_pattern[0], array('~', '!'))) {
$_pattern = substr($_pattern, 1);
if (preg_match('/^' . $_pattern . '$/i', $_token)) continue;
} else {
if (!preg_match('/^' . $_pattern . '$/i', $_token)) continue;
}
}
$_filters[$_token][] = $_filter;
}
$cache && $cache->set('filters', $_filters);
}
if (empty($_filters[$_token])) return;
/* @var $proxy WindClassProxy */
$proxy = WindFactory::createInstance(Wind::import('WIND:filter.proxy.WindClassProxy'));
$proxy->registerTargetObject($handler);
foreach ($_filters[$_token] as $value) {
$proxy->registerEventListener(
$this->factory->createInstance(Wind::import($value['class']),
array($handler->getForward(), $handler->getErrorMessage(), $this->handlerAdapter, $value)),
'doAction');
}
$handler = $proxy;
}

  

关键是这里 

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

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

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

try {
$forward = $handler->doAction($this->handlerAdapter);
$this->doDispatch($forward);
} catch (WindForwardException $e) {
$this->doDispatch($e->getForward());
} catch (WindActionException $e) {
$this->sendErrorMessage(($e->getError() ? $e->getError() : $e->getMessage()), $e->getCode());
} catch (WindException $e) {
$this->sendErrorMessage($e->getMessage(), $e->getCode());
}

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

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

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

这里很有技巧性,看看

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

  

/**
* 返回拦截链中的下一个拦截器
*
* @return WindHandlerInterceptor
*/
public function getHandler() {
if (count($this->_interceptors) <= 1) {
return $this;
}
$handler = next($this->_interceptors);
if ($handler === false) {
reset($this->_interceptors);
return null;
}
if (method_exists($handler, 'handle')) {
$handler->setHandlerInterceptorChain($this); //这里设置有什么用呢,就死为了最后一个调用过滤链的handle方法
return $handler;
}
return $this->getHandler();
}

  

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

  这个是最后执行的,过滤器一个一个执行完了,就执行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. linux网络相关

    ethtool:http://www.ibm.com/developerworks/cn/linux/1304_wangjy_ethtools/ 网卡特性:http://blog.chinaunix. ...

  2. [原]武大预选赛F题-(裸并查集+下标离散化+floyd最短路)

    Problem 1542 - F - Countries Time Limit: 1000MS Memory Limit: 65536KB Total Submit: 266 Accepted: 36 ...

  3. Entity Framework Architecture

    http://www.entityframeworktutorial.net/EntityFramework-Architecture.aspx The following figure shows ...

  4. [POJ1159]Palindrome(dp,滚动数组)

    题目链接:http://poj.org/problem?id=1159 题意:求一个字符串加多少个字符,可以变成一个回文串.把这个字符串倒过来存一遍,求这两个字符串的lcs,用原长减去lcs就行.这题 ...

  5. 总结Selenium自动化测试方法(三)WebDriver定位元素方法

    三.WebDriver定位元素 推荐使用的webdriver是firefox,因为他的firebug更能可以帮助定位页面元素使用 # create a new Firefox session cls. ...

  6. Codeforces Round #272 (Div. 2) D. Dreamoon and Sets (思维 数学 规律)

    题目链接 题意: 1-m中,四个数凑成一组,满足任意2个数的gcd=k,求一个最小的m使得凑成n组解.并输出 分析: 直接粘一下两个很有意思的分析.. 分析1: 那我们就弄成每组数字都互质,然后全体乘 ...

  7. hdu 4810 Wall Painting (组合数学+二进制)

    题目链接 下午比赛的时候没有想出来,其实就是int型的数分为30个位,然后按照位来排列枚举. 题意:求n个数里面,取i个数异或的所有组合的和,i取1~n 分析: 将n个数拆成30位2进制,由于每个二进 ...

  8. HDU 1858 Max Partial Value I

    求连续子序列的最大和 为毛简单的入门DP没有思路啊.. 学习下别人的解法,理解起来倒还是很容易的. //#define LOCAL #include <iostream> #include ...

  9. Codeforces 279 B Books

    题意:给出n本书,总的时间t,每本书的阅读时间a[i],必须按照顺序来阅读,问最多能够阅读多少本书 有点像紫书的第七章讲的那个滑动区间貌似 维护一个区间的消耗的时间小于等于t,然后维护一个区间的最大值 ...

  10. maven打包无法打包mybatis及系统配置文件问题

    <resources> <!-- mybatis映射文件 --> <resource> <directory>src/main/java/com/bsh ...