一直都有關注phpwind這個開源產品,從9.0開始就好關注拉,由於官方說把以前的代碼重寫了一遍,融入了windFramework這個框架,代碼真的挺優美的,今日在作社區的一些功能,心血來潮就參考了phpwind的代碼,確實學到了很多 php
其實外界一直說這個框架模範了yii,但我以爲這個框架必定是有java功底的人寫的,由於真的有不少java的風格和影子,不信?請看下文 java
啓動xdebug ,看下執行流程如何web
windClassProxy 是個什麼東東,我記得以前學struct2的時候也有相似的這個玩意 ,跟進去看看就知道啦數組
1 <?php 2 /** 3 * 類代理定義 4 * 5 * 經過使用類代理機制,能夠實現對類方法或屬性的監聽過濾機制.<code> 6 * //相關組件配置,只需設置 proxy爲true,就能夠經過組件工廠建立一個具備代理功能的類實例對象. 7 * <component name='windApplication' path='WIND:web.WindWebApplication' 8 * scope='singleton' proxy='true'> 9 * <properties> 10 * <property name='dispatcher' ref='dispatcher' /> 11 * <property name='handlerAdapter' ref='router' /> 12 * </properties> 13 * </component> 14 * $object = Wind::getComponents('windApplication'); 15 * $object->registerEventListener('runProcess', new Listener()); 16 * </code> 17 * @author Qiong Wu <papa0924@gmail.com> 18 * @copyright ©2003-2103 phpwind.com 19 * @license http://www.windframework.com 20 * @version $Id: WindClassProxy.php 3681 2012-06-18 02:45:28Z yishuo $ 21 * @package base 22 */ 23 class WindClassProxy { 24 /** 25 * 默認過濾鏈類型定義 26 * 27 * @var string 28 */ 29 protected $_class_interceptorChain = 'WIND:filter.WindHandlerInterceptorChain'; 30 31 /** 32 * 過濾鏈對象 33 * 34 * @var WindHandlerInterceptorChain 35 */ 36 private $_interceptorChain = null; 37 protected $_className = ''; 38 protected $_classPath = ''; 39 protected $_instance = null; 40 protected $_listener = array(); 41 42 /** 43 * @param object $targetObj 須要被代理監聽的類對象實例 默認爲null 44 */ 45 public function __construct($targetObject = null) { 46 $targetObject && $this->registerTargetObject($targetObject); 47 } 48 49 /** 50 * 註冊事件以及事件監聽類 51 * 52 * 經過調用該方法,將事件以及對事件的監聽方法註冊進來,當事件方法被調用的時候監聽的方法被觸發.例:<code> 53 * <component name='windApplication' path='WIND:web.WindWebApplication' 54 * scope='singleton' proxy='true'>...</component> 55 * $object = Wind::getComponents('windApplication'); 56 * $object->registerEventListener('runProcess', new Listener()); 57 * </code> 58 * @param object $listener 事件監聽器 59 * @param stinrg $event 被監聽的事件 60 * @return void 61 */ 62 public function registerEventListener($listener, $event) { 63 $this->_listener[$event][] = $listener; 64 } 65 66 /** 67 * 註冊目標對象,若是已經註冊了不重複註冊 68 * 69 * WindFactory中建立類代理的一段例子:<code> 70 * $instance = new Object(); 71 * $this->addClassDefinitions($alias, array('path' => $proxy, 'scope' => 'prototype')); 72 * $proxy = $this->getInstance($alias); 73 * $proxy->registerTargetObject($instance); 74 * $instance->_proxy = $proxy; 75 * </code><note><b>注意:</b>$instance繼承自WindModule</note> 76 * @param object $targetObject 77 * @return WindClassProxy 78 */ 79 public function registerTargetObject($targetObject) { 80 $this->_className = get_class($targetObject); 81 $this->_instance = $targetObject; 82 return $this; 83 } 84 85 /** 86 * 監聽類方法 87 * 88 * @param string $methodName 方法名 89 * @param array $args 方法參數 90 * @return mixed 91 * @throws WindException 92 */ 93 public function __call($methodName, $args) { 94 $listeners = isset($this->_listener[$methodName]) ? $this->_listener[$methodName] : array(); 95 if (empty($listeners)) return call_user_func_array(array($this->_instance, $methodName), $args); 96 $interceptorChain = $this->_getInterceptorChain($methodName); 97 $interceptorChain->addInterceptors($listeners); 98 $interceptorChain->setCallBack(array($this->_getInstance(), $methodName), $args); 99 return call_user_func_array(array($interceptorChain->getHandler(), 'handle'), (array) $args); 100 } 101 102 /** 103 * 建立並返回過濾鏈,若是過濾鏈已經被建立不重複建立 104 * 105 * @param string $event 事件名稱 默認值爲空 106 * @return WindHandlerInterceptorChain 107 * @throws WindException 108 */ 109 private function _getInterceptorChain($event = '') { 110 if (null === $this->_interceptorChain) { 111 $chain = Wind::import($this->_class_interceptorChain); 112 $this->_interceptorChain = WindFactory::createInstance($chain); 113 } 114 $this->_interceptorChain->reset(); 115 return $this->_interceptorChain; 116 } 117 118 /** 119 * 返回當前代理對象的真實類對象 120 * 121 * @return object 122 */ 123 public function _getInstance() { 124 return $this->_instance; 125 } 126 127 /** 128 * 返回當前代理對象的真實類名稱 129 * 130 * @return string 131 */ 132 public function _getClassName() { 133 return $this->_className; 134 } 135 136 /** 137 * 返回當前代理對象的真實類的路徑信息 138 * 139 * @return string 140 */ 141 public function _getClassPath() { 142 return $this->_classPath; 143 } 144 145 /** 146 * 設置類名稱 147 * 148 * @param string $className 149 * @return void 150 */ 151 public function _setClassName($className) { 152 $this->_className = $className; 153 } 154 155 /** 156 * 設置類路徑 157 * 158 * @param string $classPath 159 * @return void 160 */ 161 public function _setClassPath($classPath) { 162 $this->_setClassName(Wind::import($classPath)); 163 $this->_classPath = $classPath; 164 } 165 } 166 ?>
一個代理類,那麼該怎麼用呢,先看看下面把 安全
1 /** 2 * 解析action過濾鏈的配置信息 3 * 4 * @param WindSimpleController $handler 5 * @return void 6 */ 7 protected function resolveActionFilters(&$handler) { 8 if (!$filters = $this->getConfig('filters')) return; 9 /* @var $cache AbstractWindCache */ 10 $_filters = array(); 11 if ($cache = Wind::getComponent('windCache')) { 12 $_filters = $cache->get('filters'); 13 } 14 $_token = $this->handlerAdapter->getModule() . '/' . $this->handlerAdapter->getController() . '/' . $this->handlerAdapter->getAction(); 15 if (!isset($_filters[$_token])) { 16 foreach ($filters as $_filter) { 17 if (empty($_filter['class'])) continue; 18 $_pattern = empty($_filter['pattern']) ? '' : $_filter['pattern']; 19 unset($_filter['pattern']); 20 if ($_pattern) { 21 $_pattern = str_replace(array('*', '/'), array('\w*', '\/'), $_pattern); 22 if (in_array($_pattern[0], array('~', '!'))) { 23 $_pattern = substr($_pattern, 1); 24 if (preg_match('/^' . $_pattern . '$/i', $_token)) continue; 25 } else { 26 if (!preg_match('/^' . $_pattern . '$/i', $_token)) continue; 27 } 28 } 29 $_filters[$_token][] = $_filter; 30 } 31 $cache && $cache->set('filters', $_filters); 32 } 33 if (empty($_filters[$_token])) return; 34 /* @var $proxy WindClassProxy */ 35 $proxy = WindFactory::createInstance(Wind::import('WIND:filter.proxy.WindClassProxy')); 36 $proxy->registerTargetObject($handler); 37 foreach ($_filters[$_token] as $value) { 38 $proxy->registerEventListener( 39 $this->factory->createInstance(Wind::import($value['class']), 40 array($handler->getForward(), $handler->getErrorMessage(), $this->handlerAdapter, $value)), 41 'doAction'); 42 } 43 $handler = $proxy; 44 }
一系列的 filter,跟java好像把是否是 ,看下java是怎樣定義fliter的吧 cookie
1 import java.io.*; 2 import javax.servlet.*; 3 import javax.servlet.http.*; 4 import java.util.*; 5 6 // 實現 Filter 類 7 public class LogFilter implements Filter { 8 public void init(FilterConfig config) 9 throws ServletException{ 10 // 獲取初始化參數 11 String testParam = config.getInitParameter("test-param"); 12 13 // 輸出初始化參數 14 System.out.println("Test Param: " + testParam); 15 } 16 public void doFilter(ServletRequest request, 17 ServletResponse response, 18 FilterChain chain) 19 throws java.io.IOException, ServletException { 20 21 // 獲取客戶機的 IP 地址 22 String ipAddress = request.getRemoteAddr(); 23 24 // 記錄 IP 地址和當前時間戳 25 System.out.println("IP "+ ipAddress + ", Time " 26 + new Date().toString()); 27 28 // 把請求傳回過濾鏈 29 chain.doFilter(request,response); 30 } 31 public void destroy( ){ 32 /* 在 Filter 實例被 Web 容器從服務移除以前調用 */ 33 } 34 }
1 <filter> 2 <filter-name>LogFilter</filter-name> 3 <filter-class>LogFilter</filter-class> 4 <init-param> 5 <param-name>test-param</param-name> 6 <param-value>Initialization Paramter</param-value> 7 </init-param> 8 </filter> 9 <filter-mapping> 10 <filter-name>LogFilter</filter-name> 11 <url-pattern>/*</url-pattern> 12 </filter-mapping>
是否是好像阿,看下這段代碼 app
1 $_token = $this->handlerAdapter->getModule() . '/' . $this->handlerAdapter->getController() . '/' . $this->handlerAdapter->getAction(); 2 if (!isset($_filters[$_token])) { 3 foreach ($filters as $_filter) { 4 if (empty($_filter['class'])) continue; 5 $_pattern = empty($_filter['pattern']) ? '' : $_filter['pattern']; 6 unset($_filter['pattern']); 7 if ($_pattern) { 8 $_pattern = str_replace(array('*', '/'), array('\w*', '\/'), $_pattern); 9 if (in_array($_pattern[0], array('~', '!'))) { 10 $_pattern = substr($_pattern, 1); 11 if (preg_match('/^' . $_pattern . '$/i', $_token)) continue; 12 } else { 13 if (!preg_match('/^' . $_pattern . '$/i', $_token)) continue; 14 } 15 } 16 $_filters[$_token][] = $_filter; 17 } 18 $cache && $cache->set('filters', $_filters); 19 }
若是url匹配的話,該過濾器就加入執行隊列裏面框架
看看phpwind的過濾器是怎樣書寫的yii
<?php Wind::import('WIND:filter.WindActionFilter'); /** * * CSRF安全處理filter * * @author liusanbian <liusanbian@aliyun.com> * @copyright ©2003-2103 phpwind.com * @license http://www.windframework.com * @version $Id$ */ class PwCsrfTokenFilter extends WindActionFilter { /* (non-PHPdoc) * @see WindHandlerInterceptor::preHandle() */ public function preHandle() { if (true !== $this->getRequest()->isPost() || empty($_POST)) return ; /* @var $windToken IWindSecurityToken */ $windToken = Wind::getComponent('windToken'); $csrf_token = $this->getInput('csrf_token', 'POST'); if (true !== $windToken->validateToken($csrf_token, 'csrf_token')) { $this->errorMessage->sendError('Sorry, CSRF verification failed(token missing or incorrect),refresh to try again.'); } } /* (non-PHPdoc) * @see WindHandlerInterceptor::postHandle() */ public function postHandle() {} } ?>
簡直就是殊途同歸阿 ,再看看它的父類 函數
<?php Wind::import('WIND:fitler.WindHandlerInterceptor'); /** * action攔截器父類 * 繼承實現攔截鏈preHandle(前置)和postHandle(後置)職責.將實現的攔截鏈添加到應用配置中,使之生效: * 例如實現MyFilter,則須要在應用配置中添加以下配置: * <code> * 'filters' => array( * 'class' => 'WIND:filter.WindFilterChain', //設置使用的攔截鏈實現 * 'filter1' => array( * 'class' => * 'MYAPP:filter.MyFilter', //設置設置實現的MyFilter類路徑,MYAPP必須是一個有效的通過註冊的命名空間 * 'pattern' => '*', //此處設置該攔截規則應用的範圍,*意味着全部的action都將會應用該攔截規則 * ) * ) * </code> * 關於pattern的設置說明以下: * <ul> * <li>*:則全部的請求都將會應用該攔截器</li> * <li>moduleA*: 則全部配置的moduleA模塊下的請求都將會應用該攔截器</li> * <li>moduleA_index*: 則moduleA模塊下的indexController下的全部Action請求都將會應用該攔截器</li> * <li>moduleA_index_add*: 則module模塊下的indexController下的addAction將會應用該攔截器</li> * </ul> * 用戶能夠在filter中添加本身的特殊配置:好比: * <code> * 'filters' => array( * 'class' => 'WIND:filter.WindFilterChain', * 'filter1' => array( * 'class' => 'MYAPP:filter.TestFilter', * 'pattern' => '*', * 'isOpen' => '1', //添加的配置 * ) * ) * </code> * 則在本身的TestFilter中設置一個屬性名爲isOpen同時設置該屬性爲protected權限,那麼在使用的時候該配置的值將會賦值給該屬性. * * @author Qiong Wu <papa0924@gmail.com> * @copyright ©2003-2103 phpwind.com * @license http://www.windframework.com * @version $Id: WindActionFilter.php 3829 2012-11-19 11:13:22Z yishuo $ * @package filter */ abstract class WindActionFilter extends WindHandlerInterceptor { /** * action跳轉類 * * @var WindForward */ protected $forward = null; /** * 錯誤處理類 * * @var WindErrorMessage */ protected $errorMessage = null; /** * 路由對象 * * @var AbstractWindRouter */ protected $router = null; /** * 構造函數 * 初始化類屬性 * * @param WindForward $forward * 設置當前的forward對象 * @param WindErrorMessage $errorMessage * 設置錯誤處理的errorMessage * @param AbstractWindRouter $router * 路由對象 * @param array $args * 接受數組傳遞,數組以關聯數組的方式給出,若是存在屬性和關聯數組中的key相同則將該key對應值設置給該屬性. */ public function __construct($forward, $errorMessage, $router, $args = array()) { $this->forward = $forward; $this->errorMessage = $errorMessage; $this->router = $router; foreach ($args as $key => $value) property_exists($this, $key) && $this->$key = $value; } /** * 設置模板數據 * 此方法設置的參數,做用域僅僅只是在當前模板中可用,調用的方法爲{$varName} * * @param string|array|object $data * 須要設置輸出的參數 * @param string $key * 參數的名字,默認爲空,若是key爲空,而且$data是數組或是對象的時候,則$data中的元素將會做爲單獨的參數保存到輸出數據中. */ protected function setOutput($data, $key = '') { $this->forward->setVars($data, $key); } /** * 從指定源中根據輸入的參數名得到輸入數據 * * @param string $name * 須要獲取的值的key * @param string $type * 獲取數據源,能夠是(GET POST COOKIE)中的一個,每種都將從各自的源中去獲取對應的數值: * <ul> * <li>GET: 將從$_GET中去獲取數據</li> * <li>POST: 將從$_POST中去獲取數據</li> * <li>COOKIE: 將從$_COOKIE中去獲取數據</li> * <li>其餘值: * 將依次從request對象的attribute,$_GET,$_POST,$_COOKIE,$_REQUEST,$_ENV,$_SERVER中去嘗試獲取該值.</li> * </ul> * 該參數默認爲空 * @return array string <ul> * <li>第一個元素: 得到的用戶輸入的值</li> * <li>第二個元素:執行$callback以後返回的值</li> * </ul> */ protected function getInput($name, $type = '') { $value = ''; switch (strtolower($type)) { case 'get': $value = $this->getRequest()->getGet($name); break; case 'post': $value = $this->getRequest()->getPost($name); break; case 'cookie': $value = $this->getRequest()->getCookie($name); break; default: $value = $this->getRequest()->getRequest($name); } return $value; } } ?>
下面這個類纔是關鍵
<?php /** * 攔截器基類 * * 該類是攔截器機制的核心實現,提供接口: * <ul> * <li>{@link preHandle()}: 抽象接口,前置操做,須要子類實現</li> * <li>{@link postHandle()}: 抽象接口,後置操做,須要子類實現</li> * <li>{@link handle()}: 入口接口,調用攔截器的實現.</li> * </ul> * 該攔截器須要配合攔截鏈WindHandlerInterceptorChain實現真正的攔截鏈. * * the last known user to change this file in the repository <$LastChangedBy: yishuo $> * @author Qiong Wu <papa0924@gmail.com> * @copyright ©2003-2103 phpwind.com * @license http://www.windframework.com * @version $Id: WindHandlerInterceptor.php 3113 2011-11-11 07:28:09Z yishuo $ * @package filter */ abstract class WindHandlerInterceptor extends WindModule { /** * 保存執行的結果 * * @var mixed */ protected $result = null; /** * 保存攔截鏈 * * 用以傳遞控制到下一個攔截器 * * @var WindHandlerInterceptorChain */ protected $interceptorChain = null; /** * 攔截器的前置操做 * * @param mixed $var=.. 參數列表將會從handle接口中傳遞繼承 * @return null|mixed 若是返回爲null則將會繼續執行下一個攔截器,若是返回不爲null則會中斷攔截鏈的執行 */ abstract public function preHandle(); /** * 攔截器的後置操做 * * @param mixed $var=.. 參數列表將會從handle接口中傳遞繼承 */ abstract public function postHandle(); /** * 攔截器的執行入口 * * @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); } else { $this->result = call_user_func_array(array($this->interceptorChain, 'handle'), $args); } call_user_func_array(array($this, 'postHandle'), $args); return $this->result; } /** * 設置攔截鏈對象 * * @param WindHandlerInterceptorChain $interceptorChain */ public function setHandlerInterceptorChain($interceptorChain) { $this->interceptorChain = $interceptorChain; } } ?>
preHandle 和 postHandle 這兩個方法是抽象的,須要子類實現的,handle這個東西能夠在子類調用阿
並且 setHandlerInterceptorChain 這個能夠換不一樣的攔截器鏈,比較靈活把
今日就分享到這裏吧,下節再繼續
---恢復內容結束---