捣蛋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 ...
随机推荐
- framwork NHibernate
NHibernate 一.NHibernate 1.HQL curd语句总结 . 查询整个映射对象所有字段 ? //直接from查询出来的是一个映射对象,即:查询整个映射对象所有字段 String ...
- Failed to load unit 'HGCM' (VERR_INVALID_PARAMETER)
1 清除状态: clear the state, 显示 边上有个 清楚 按钮,作用相当于重启虚拟机 restart
- 【笔记】一些linux实用函数技巧【原创】
函数返回的是函数的地址 kallsyms_lookup_name()
- flex 4 Filters
<s:RectangularDropShadow id="dropShadow" blurX="10" blurY="10" alph ...
- CMD下查看某个端口被谁占用了
cmd运行 netstat -aon|findstr "8080" 运行结果如下 TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 6416 TCP [:: ...
- 字符串 —— String?StringBuffer?StringBuilder?
字符串常用的操作就是拼接,特别是SQL语句的拼接. 做了个简单的试验,它们之间的差别惊人! StringBuffer: public void testStringBuffer() { long st ...
- javascript callback函数的理解与使用
最近做的一个项目中用到了callback函数,于是就研究了下总结下我对javascript callback的理解 首先从callback的字面翻译“回调” 可以理解这是一个函数被调用的机制 当我们遇 ...
- 同步synchronized用法
今天在高人的指导下,对同步synchronized用法有了更高一层的理解,非常感谢他的无私奉献.在此把代码贴出来方便日后查阅. publicclass SfServlet { privatestati ...
- Asp.Net使用代理IP远程获取数据
/// <summary> /// 远程获取数据 /// </summary> /// <param name="url">url</pa ...
- HDU 1496 Train Problem I 火车问题1(桟,水)
题意: 给出两个串,串中的数字i 代表编号为i的火车进入车站的顺序,车站如桟一样,先进后出.第二个串是火车出站的顺序,问若按照第一个串那样进站,是否有可能如第二个串一样的出站顺序?火车顶多9辆,即1- ...