捣蛋phpwind过滤器执行流程

China☆狼群 提交于 2020-02-15 16:03:17

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

 

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

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!