捣蛋phpwind过滤器执行流程
从上一篇我们就大概就知道过滤器的定义和怎样去配置,这一节来说说执行流程
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过滤器执行流程的更多相关文章
- 捣蛋phpwind之WindFrameWork
一直都有关注phpwind这个开源产品,从9.0开始就好关注拉,因为官方说把之前的代码重写了一遍,融入了windFramework这个框架,代码真的挺优美的,今日在做社区的一些功能,心血来潮就参考了p ...
- 轻量级前端MVVM框架avalon - 执行流程2
接上一章 执行流程1 在这一大堆扫描绑定方法中应该会哪些实现? 首先我们看avalon能帮你做什么? 数据填充,比如表单的一些初始值,切换卡的各个面板的内容({{xxx}},{{xxx|html}}, ...
- ThinkPHP2.2框架执行流程图,ThinkPHP控制器的执行流程
ThinkPHP2.2框架执行原理.流程图在线手册 ThinkPHP控制器的执行流程 对用户的第一次URL访问 http://<serverIp>/My/index.php/Index/s ...
- Servlet、Struts2、SpringMVC执行流程
Servlet 有以下四个阶段: 1.加载和实例化 Servlet容器负责加载和实例化Servlet. 当Servlet容器启动时,或者在容器检测到需要这个Servlet来响应第一个请求时,创建Ser ...
- struts2 之 【struts2简介,struts2开发步骤,struts2详细配置,struts2执行流程】
入门框架学习避免不了的问题: 1. 什么是框架? 简单的说,框架就是模板,模子,模型.就是一个可重用的半成品. 2. 如何学习框架? 学习框架其实就是学习规则,使用框架就是遵循框架的规则,框架是可变的 ...
- Struts框架之 执行流程 struts.xml 配置详细
1.执行流程 服务器启动: 1. 加载项目web.xml 2. 创建Struts核心过滤器对象, 执行filter → init() struts-default.xml, 核心功能的初 ...
- Struts2第二篇【开发步骤、执行流程、struts.xml讲解、defalut-struts讲解】
前言 我们现在学习的是Struts2,其实Struts1和Struts2在技术上是没有很大的关联的.Struts2其实基于Web Work框架的,只不过它的推广没有Struts1好,因此就拿着Stru ...
- Spring Security Oauth2 单点登录案例实现和执行流程剖析
Spring Security Oauth2 OAuth是一个关于授权的开放网络标准,在全世界得到的广泛的应用,目前是2.0的版本.OAuth2在“客户端”与“服务提供商”之间,设置了一个授权层(au ...
- Spring Security 案例实现和执行流程剖析
Spring Security Spring Security 是 Spring 社区的一个顶级项目,也是 Spring Boot 官方推荐使用的安全框架.除了常规的认证(Authentication ...
随机推荐
- ubuntu下安装与测试mysql
1.在决定安装mysql之前,要先确定系统是否已经安装mysql. 输入: 1 mysql 结果:说明尚未安装mysql The program 'mysql' is currently notins ...
- linux poll
man poll: NAME poll, ppoll - wait for some event on a file descriptor SYNOPSIS #include <poll.h&g ...
- PowerDesigner建立与数据库的连接,以便生成数据库和从数据库生成到PD中。
第一步,打开PD15,找到[Database],如图所示: 第二步,点击新建按钮,创建一个新的ODBC连接. 第三步,这里选择系统数据源,并选择Oracle 第四步,这里需要注意,服务器需要写的是Or ...
- SQL注入实验,PHP连接数据库,Mysql查看binlog,PreparedStatement,mysqli, PDO
看到有人说了判断能否sql注入的方法: 简单的在参数后边加一个单引号,就可以快速判断是否可以进行SQL注入,这个百试百灵,如果有漏洞的话,一般会报错. 下面内容参考了这两篇文章 http://blog ...
- Java C++ Python PHP JS等各种语言中的INT最值
Java: Integer.MAX_VALUE; Integer.MIN_VALUE; C++ INT_MAX INT_MIN <limit.h> 有些其他头文件也有引用 Python & ...
- Machine Learning for hackers读书笔记(四)排序:智能收件箱
#数据集来源http://spamassassin.apache.org/publiccorpus/ #加载数据 library(tm)library(ggplot2)data.path<-'F ...
- UVa 10905 Children's Game
注意!这不是单纯的字典序排序,比如90.9,应该是990最大 对字符串排序蛋疼了好久,因为别人说string很慢,所以一直没有用过. 看别人用string还是比较方便的,学习一下 对了,这里的cmp函 ...
- 转载]IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本 )
原文地址:IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本作者:佐佐木小次郎 因为最近项目上要用有关LBS的功能.于是我便做一下预研. 一般说来LBS功能一般分为两块:一块是地理 ...
- 13.Object-C--浅谈Foundation框架常用的结构体
------- android培训.iOS培训.期待与您交流! ---------- 昨天学习了Foundation框架中常用的结构体,下面我简单的总结一下,如果错误麻烦请留言指正,谢谢! Found ...
- 关于jsp利用EL和struts2标签来遍历ValueStack的东东 ------> List<Map<K,V>> 以及 Map<K,<List<xxx>>> 的结构遍历
//第一种结构Map<K,<List<xxx>>> <body> <% //显示map<String,List<Object>& ...