捣蛋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 ...
随机推荐
- weka数据挖掘拾遗(三)----再谈如果何生成arff
前一阵子写过一个arff的随笔,但是写完后发现有些啰嗦.其实如果使用weka自带的api,生成arff文件将变成一件很简单的事儿. 首先,可以先把特征文件生成csv格式的.csv格式就是每列数据都用逗 ...
- PHP 简介
lamp LAMP - Linux Apache MySQL PHP MySQL - 三个层次:文件层次,服务层次,界面层次. LAMP-Linux Apache MySQL PHP 本机 :127. ...
- eclipse中servers(服务器)的配置
eclipse中servers(服务器)的配置 使用eclipse+tomcat时,很多人喜欢安装tomcat插件,以便一键启动tomcat,但我不喜欢给eclipse安装一些非必须的插件,而ecli ...
- jdbc框架 commons-dbutils的使用
commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序 ...
- 深入理解Java内存模型(三)——顺序一致性
数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数据竞争的定义如下: 在一个线程中写一个变量, 在另一个线程读同一个变量, 而且写和读没有通过同步来排序. 当代码 ...
- 你猜……你再猜
『男』:你喜欢我吗? 『女』:你猜. 『男』:喜欢. 『女』:你再猜. 『男』:--
- 谈谈Perforce
实习就要结束了,收获之一就是学会了使用Perforce! Perforce SCM System是一款构建于可伸缩客户/服务器结构之上的软件配置管理工具.仅仅应用 TCP/IP,开发人员就能够通过多种 ...
- 不同浏览器JS获取浏览器高度和宽度
摘自:http://blog.csdn.net/lai_gb/archive/2009/07/04/4320956.aspx IE中: document.body.clientWidth ==> ...
- HeadFirst 12 (web应用安全)
测试领域可以使用的方法,在tomcat-users.xml 中设置授权, 为什么这个不能在生产环境中呢, 因为如果这个设置在生产环境中, 那么当你想修改”授权时”, 就要修改这个xml文件, 那么就要 ...
- PDO(PHP Data Object),Mysqli,以及对sql注入等问题的解决
这篇是上一篇 http://www.cnblogs.com/charlesblc/p/5987951.html 的续集. 看有的文章提到mysqli和PDO都支持多重查询,所以下面的url会造成表数据 ...