從上一篇咱們就大概就知道過濾器的定義和怎樣去配置,這一節來講說執行流程 php
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這個屬性,這個變量到底裏面裝的是什麼呢函數
咱們在控制檯看一下把post
我這裏解釋一下把,這裏的this是windClassProxy的實例,還記得它是怎樣建立的嗎,再貼一下這個代碼this
/** * 解析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; }
關鍵是這裏 spa
$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'); }
建立一個代理類,而後幫定一個事件,把過濾器做爲事件處理其實例化而後等下觸發,不知道爲何要這樣作,想得不是很明白代理
好啦,萬事俱備,只欠東風拉,看看它是這樣運做拉server
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的魔術方法拉,以下blog
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,若是沒有,就直接地調用算啦,若是有的話,就加入到鏈條裏token
這裏頗有技巧性,看看接口
* 攔截器的執行入口 * * @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拉 ,有時間畫一個圖出來會比較容易理解拉