首页 > Windows开发 > 详细

捣蛋phpwind之WindFrameWork

时间:2015-12-23 23:01:00      阅读:1180      评论:0      收藏:0      [点我收藏+]

 

        一直都有关注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 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的吧 

 

 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.xml 中的 Servlet 过滤器映射(Servlet Filter Mapping)

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

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

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




 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

捣蛋phpwind之WindFrameWork

原文:http://www.cnblogs.com/simonlu/p/5071482.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!