捣蛋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拉 ,有时间画一个图出来会比较容易理解拉 

时间: 2024-10-13 06:55:36

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

程序执行流程(粗略)

程序执行流程(粗略) 用户发出请求 前台进行js规则验证(良好的用户体验) 按照一定的规则进行数据提交 (数据没有封装的提交 和 数据封装过后的提交) 控制层进行数据的接收 1.进行数据的非空.规则验证 || 规则验证可以读取配置文件 2.处理session信息 3.进行权限的验证 || 可以使用权限拦截器或过滤器 # 分清数据来源::: 来源于用户输入(输入数据 ), 来源于系统生成(当前时间) , 默认值在业务层之中设置保证业务的可移植性 # 在调用业务之前一定要保证将业务需要的信息已经进行

走进Struts2(一) — Struts2的执行流程及其工作原理

 Struts2是一套很优秀的Web应用框架,实现优雅.功能强大.使用简洁.能够说是Struts2是一款很成熟的MVC架构. 在我们学习Struts2时,最好是先学习它的执行流程.核心概念.从中得到启示.提升自己,而不不过学习怎么怎么使用它. 在网上看到这样一句话: 你千万不要成为一个仅仅会熟练使用框架的程序猿.那样.你会疲于奔命,你或许永远仅仅会使用 Hadoop ,而写不出一个 Hadoop ,你仅仅是一个 Hadoop程序猿,而不是一个分布式project师. 你或许永远仅仅会使用 Str

图文解析Struts2框架执行流程

struts的架构图 (1)提交请求 客户端通过HttpServletRequest向servlet容器(即tomcat)提交一个请求. 请求经过一系列的过滤器,例如图中的ActionContextCleanUp和Other filter(SlterMesh,etc)等,最后被struts的核心过滤器FilterDispatcher控制到. 注:核心控制器2.1.3版本之后,struts的filterDispatcher核心控制器变成了StrutsPrepareAndExecuteFilte,如

Servlet、Struts2、SpringMVC执行流程

Servlet 有以下四个阶段: 1.加载和实例化 Servlet容器负责加载和实例化Servlet. 当Servlet容器启动时,或者在容器检测到需要这个Servlet来响应第一个请求时,创建Servlet实例. 当Servlet容器启动后,它必须要知道所需的Servlet类在什么位置,Servlet容器可以从本地文件系统.远程文件系统或者其他的网络服务中通过类加载器加载Servlet类,成功加载后,容器创建Servlet的实例. 因为容器是通过Java的反射API来创建 Servlet实例,

yii执行流程

yii执行流程 原文:http://www.cnblogs.com/bluecobra/archive/2011/11/30/2269207.html 一 目录文件 |-framework     框架核心库 |--base         底层类库文件夹,包含CApplication(应用类,负责全局的用户请求处理,它管理的应用组件集,将提供特定功能给整个应用程序),CComponent(组件类,该文件包含了基于组件和事件驱动编程的基础类,从版本1.1.0开始,一个行为的属性(或者它的公共成员

struts2的执行流程与配置详解

本章主要讲解Struts的执行流程以及Struts的配置以及访问servletApi 全部代码下载: github链接:链接 写文章不易,欢迎大家采我的文章,以及给出有用的评论,当然大家也可以关注一下我的github:多谢: 1.Struts的执行流程: 1.服务器启动时: 加载项目web.xml 创建Struts核心过滤器对象, 执行StrutsPrepareAndExecuteFilter的doFilter 的 init()方法: 在StrutsPrepareAndExecuteFilter

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

入门框架学习避免不了的问题: 1. 什么是框架? 简单的说,框架就是模板,模子,模型.就是一个可重用的半成品. 2. 如何学习框架? 学习框架其实就是学习规则,使用框架就是遵循框架的规则,框架是可变的 和 不可变的部分组成,学习框架就需要把 什么可变什么不可变搞清楚. 3. 为什么使用 struts2 框架:聊这个问题先来聊一聊 Web的开发模式, model1 和 model2 模式. 4. model1模式:jsp+javaBean开发. 优点:执行效率高,代码比较少,开发效率比较高.适合小

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

ThinkPHP2.2框架执行原理.流程图在线手册 ThinkPHP控制器的执行流程 对用户的第一次URL访问 http://<serverIp>/My/index.php/Index/show/ 所执行的流程进行详细的分析,用户的URL访问首先是定位到了My项目的index.php 入口文件(注意:如果使用了URL_REWRITE,可能index.php已经被隐藏了),项目的入口文件所做的其实是实例化一个App应用实例,并且执行这个应用. 1.加载公共入口文件 在实例化App类之前,我们需要

struts2执行流程与拦截器介绍

struts2执行流程介绍 1.客户端向Servlet容器(如Tomcat)提交一个请求 2.请求经过一系列过滤器(如ActionContextCleanUp过滤器等) 3.核心控制器被调用,询问ActionMapper来决定请求是否需要调用某个Action 4.如果ActionMapper决定需要调用某个Action,核心控制器把控制权委派给ActionProxy (备注:JSP请求无需调用Action) 5.ActionProxy通过Configuration Manager询问框架的配置文