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