捣蛋phpwind之WindFrameWork

时间:2024-01-19 08:22:38

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

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

捣蛋phpwind之WindFrameWork

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

捣蛋phpwind之WindFrameWork

windClassProxy 是个什么东东,我记得之前学struct2的时候也有类似的这个玩意 ,跟进去看看就知道啦

 <?php
/**
* 类代理定义
*
* 通过使用类代理机制,可以实现对类方法或属性的监听过滤机制.<code>
* //相关组件配置,只需设置 proxy为true,就可以通过组件工厂创建一个具有代理功能的类实例对象.
* <component name='windApplication' path='WIND:web.WindWebApplication'
* scope='singleton' proxy='true'>
* <properties>
* <property name='dispatcher' ref='dispatcher' />
* <property name='handlerAdapter' ref='router' />
* </properties>
* </component>
* $object = Wind::getComponents('windApplication');
* $object->registerEventListener('runProcess', new Listener());
* </code>
* @author Qiong Wu <papa0924@gmail.com>
* @copyright ©2003-2103 phpwind.com
* @license http://www.windframework.com
* @version $Id: WindClassProxy.php 3681 2012-06-18 02:45:28Z yishuo $
* @package base
*/
class WindClassProxy {
/**
* 默认过滤链类型定义
*
* @var string
*/
protected $_class_interceptorChain = 'WIND:filter.WindHandlerInterceptorChain'; /**
* 过滤链对象
*
* @var WindHandlerInterceptorChain
*/
private $_interceptorChain = null;
protected $_className = '';
protected $_classPath = '';
protected $_instance = null;
protected $_listener = array(); /**
* @param object $targetObj 需要被代理监听的类对象实例 默认为null
*/
public function __construct($targetObject = null) {
$targetObject && $this->registerTargetObject($targetObject);
} /**
* 注册事件以及事件监听类
*
* 通过调用该方法,将事件以及对事件的监听方法注册进来,当事件方法被调用的时候监听的方法被触发.例:<code>
* <component name='windApplication' path='WIND:web.WindWebApplication'
* scope='singleton' proxy='true'>...</component>
* $object = Wind::getComponents('windApplication');
* $object->registerEventListener('runProcess', new Listener());
* </code>
* @param object $listener 事件监听器
* @param stinrg $event 被监听的事件
* @return void
*/
public function registerEventListener($listener, $event) {
$this->_listener[$event][] = $listener;
} /**
* 注册目标对象,如果已经注册了不重复注册
*
* WindFactory中创建类代理的一段例子:<code>
* $instance = new Object();
* $this->addClassDefinitions($alias, array('path' => $proxy, 'scope' => 'prototype'));
* $proxy = $this->getInstance($alias);
* $proxy->registerTargetObject($instance);
* $instance->_proxy = $proxy;
* </code><note><b>注意:</b>$instance继承自WindModule</note>
* @param object $targetObject
* @return WindClassProxy
*/
public function registerTargetObject($targetObject) {
$this->_className = get_class($targetObject);
$this->_instance = $targetObject;
return $this;
} /**
* 监听类方法
*
* @param string $methodName 方法名
* @param array $args 方法参数
* @return mixed
* @throws WindException
*/
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);
} /**
* 创建并返回过滤链,如果过滤链已经被创建不重复创建
*
* @param string $event 事件名称 默认值为空
* @return WindHandlerInterceptorChain
* @throws WindException
*/
private function _getInterceptorChain($event = '') {
if (null === $this->_interceptorChain) {
$chain = Wind::import($this->_class_interceptorChain);
$this->_interceptorChain = WindFactory::createInstance($chain);
}
$this->_interceptorChain->reset();
return $this->_interceptorChain;
} /**
* 返回当前代理对象的真实类对象
*
* @return object
*/
public function _getInstance() {
return $this->_instance;
} /**
* 返回当前代理对象的真实类名称
*
* @return string
*/
public function _getClassName() {
return $this->_className;
} /**
* 返回当前代理对象的真实类的路径信息
*
* @return string
*/
public function _getClassPath() {
return $this->_classPath;
} /**
* 设置类名称
*
* @param string $className
* @return void
*/
public function _setClassName($className) {
$this->_className = $className;
} /**
* 设置类路径
*
* @param string $classPath
* @return void
*/
public function _setClassPath($classPath) {
$this->_setClassName(Wind::import($classPath));
$this->_classPath = $classPath;
}
}
?>

一个代理类,那么该怎么用呢,先看看下面把

     /**
* 解析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;
}

捣蛋phpwind之WindFrameWork

一系列的 filter,跟java好像把是不是 ,看下java是怎样定义fliter的吧

 import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*; // 实现 Filter 类
public class LogFilter implements Filter {
public void init(FilterConfig config)
throws ServletException{
// 获取初始化参数
String testParam = config.getInitParameter("test-param"); // 输出初始化参数
System.out.println("Test Param: " + testParam);
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws java.io.IOException, ServletException { // 获取客户机的 IP 地址
String ipAddress = request.getRemoteAddr(); // 记录 IP 地址和当前时间戳
System.out.println("IP "+ ipAddress + ", Time "
+ new Date().toString()); // 把请求传回过滤链
chain.doFilter(request,response);
}
public void destroy( ){
/* 在 Filter 实例被 Web 容器从服务移除之前调用 */
}
}

Web.xml 中的 Servlet 过滤器映射(Servlet Filter Mapping)

 <filter>
<filter-name>LogFilter</filter-name>
<filter-class>LogFilter</filter-class>
<init-param>
<param-name>test-param</param-name>
<param-value>Initialization Paramter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

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

 $_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);
}

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

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

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