你的位置:首页 > ASP.net教程

[ASP.net教程]捣蛋phpwind之WindFrameWork


 

        一直都有关注phpwind这个开源产品,从9.0开始就好关注拉,因为官方说把之前的代码重写了一遍,融入了windFramework这个框架,代码真的挺优美的,今日在做社区的一些功能,心血来潮就参考了phpwind的代码,确实学到了不少 

其实外界一直说这个框架模范了yii,但我觉得这个框架一定是有java功底的人写的,因为真的有很多java的风格和影子,不信?请看下文 

       

启动xdebug ,看下执行流程如何

 

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 WindHandlerInterceptorChain107    * @throws WindException108   */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 object122   */123   public function _getInstance() {124     return $this->_instance;125   }126 127   /**128    * 返回当前代理对象的真实类名称129    * 130    * @return string131   */132   public function _getClassName() {133     return $this->_className;134   }135 136   /**137    * 返回当前代理对象的真实类的路径信息138    * 139    * @return string140   */141   public function _getClassPath() {142     return $this->_classPath;143   }144 145   /**146    * 设置类名称147    * 148    * @param string $className149    * @return void150   */151   public function _setClassName($className) {152     $this->_className = $className;153   }154 155   /**156    * 设置类路径157    * 158    * @param string $classPath159    * @return void160   */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的吧 

 

 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 }

Web.
 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>

是不是好像阿,看下这段代码 

 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的过滤器是怎样书写的

<?phpWind::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() {}}?>

  

简直就是异曲同工阿 ,再看看它的父类 

<?phpWind::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  这个可以换不同的拦截器链,比较灵活把

今日就分享到这里吧,下节再继续




 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---恢复内容结束---