Yii PHP 框架分析(二)
Yii PHP 框架分析(二)
作者:wdy
http://hi.baidu.com/delphiss/blog/item/54597af595085ad3f3d38552.html
Yii是基于组件(component-based)的web框架,CComponent类是所有组件的基类。
CComponent类为子类提供了基于属性(property)、事件(event)、行为(behavior)编程接口。
组件的属性(property)
Ccomponent类并没有提供属性的变量存储,需要由子类来提供两个方法来实现。子类的getPropertyName()方法提供$component->PropertyName的取值操作数据,子类的setPropertyName($val)方法提供$component->PropertyName赋值操作。
$width=$component->textWidth; // 获取 textWidth 属性
实现方式为调用子类提供的方法 $width=$component->getTextWidth()
$component->textWidth=$width; // 设置 textWidth 属性
实现方式为调用子类提供的方法 $component->setTextWidth($width)
public function getTextWidth()
{
return $this->_textWidth;
}
public function setTextWidth($value)
{
$this->_textWidth=$value;
}
组件的属性值是大小写不敏感的(类的成员时大小写敏感的)
组件的事件(event)
组件事件是一种特殊的属性,它可以将事件处理句柄(可以是函数名、类方法或对象方法)注册(绑定)到一个事件名上,句柄在事件被唤起的时候被自动调用。
组件事件存放在CComponent 的$_e[]数组里,数组的键值为事件的名字,键值的数值为一个Clist对象,Clist是Yii提供的一个队列容器,Clist的方法add()添加事件的回调handle。
//添加一个全局函数到事件处理
$component-> onBeginRequest=”logRequest”;
//添加一个类静态方法到事件处理
$component-> onBeginRequest=array(“CLog”,” logRequest”);
//添加一个对象方法到事件处理
$component-> onBeginRequest=array($mylog,” logRequest”);
唤起事件:
$component ->raiseEvent('onBeginRequest ', $event);
会自动调用:
logRequest($event), Clog:: logRequest($event)和$mylog.logRequest($event)
事件句柄必须按照如下来定义 :
function methodName($event)
{
......
}
$event 参数是 CEvent 或其子类的实例,它至少包含了"是谁挂起了这个事件"的信息。
事件的名字以”on”开头,在__get()和__set()里可以通过这个来区别属性和事件。
组件行为(behavior)
组件的行为是一种不通过继承而扩展组件功能的方法(参见设计模式里的策略模式)。
行为类必须实现 IBehavior 接口,大多数行为可以从 CBehavior 基类扩展而来。
IBehavior接口提供了4个方法。
attach($component)将自身关联到组件,detach($component) 解除$component关联,getEnabled()和setEnabled()设置行为对象的有效性。
行为对象存放在组件的$_m[]数组里,数组键值为行为名字符串,数组值为行为类对象。
组件通过attachBehavior ($name,$behavior)来扩展一个行为:
$component-> attachBehavior (‘render’,$htmlRender)
为$component添加了一个名字为render的行为,$htmlRender 需是一个实现 IBehavior 接口的对象,或是一个数组:
array( 'class'=>'path.to.BehaviorClass',
'property1'=>'value1',
'property2'=>'value2',
* )
会根据数组的class来创建行为对象并设置属性值。
$htmlRender被存储到$_m[‘render’]中。
外部调用一个组件未定义的方法时,魔术方法__call() 会遍历所有行为对象,如果找到同名方法就调用之。
例如 $htmlRender 有个方法 renderFromFile(),则可以直接当做组件的方法来访问:
$component-> renderFromFile ()
CComponent源码分析
//所有部件的基类
class CComponent
{
private $_e;
private $_m;
//获取部件属性、事件和行为的magic method
public function __get($name)
{
$getter='get'.$name;
//是否存在属性的get方法
if(method_exists($this,$getter))
return $this->$getter();
//以on开头,获取事件处理句柄
else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
{
// 事件名小写
$name=strtolower($name);
// 如果_e[$name] 不存在,返回一个空的CList事件句柄队列对象
if(!isset($this->_e[$name]))
$this->_e[$name]=new CList;
// 返回_e[$name]里存放的句柄队列对象
return $this->_e[$name];
}
// _m[$name] 里存放着行为对象则返回
else if(isset($this->_m[$name]))
return $this->_m[$name];
else
throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
array('{class}'=>get_class($this), '{property}'=>$name)));
}
/**
* PHP magic method
* 设置组件的属性和事件
*/
public function __set($name,$value)
{
$setter='set'.$name;
//是否存在属性的set方法
if(method_exists($this,$setter))
$this->$setter($value);
//name以on开头,这是事件处理句柄
else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
{
// 事件名小写
$name=strtolower($name);
// _e[$name] 不存在则创建一个CList对象
if(!isset($this->_e[$name]))
$this->_e[$name]=new CList;
// 添加事件处理句柄
$this->_e[$name]->add($value);
}
// 属性没有set方法,只有get方法,为只读属性,抛出异常
else if(method_exists($this,'get'.$name))
throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
array('{class}'=>get_class($this), '{property}'=>$name)));
else
throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
array('{class}'=>get_class($this), '{property}'=>$name)));
}
/**
* PHP magic method
* 为isset()函数提供是否存在属性和事件处理句柄的判断
*/
public function __isset($name)
{
$getter='get'.$name;
if(method_exists($this,$getter))
return $this->$getter()!==null;
else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
{
$name=strtolower($name);
return isset($this->_e[$name]) && $this->_e[$name]->getCount();
}
else
return false;
}
/**
* PHP magic method
* 设置属性值为空或删除事件名字对应的处理句柄
*/
public function __unset($name)
{
$setter='set'.$name;
if(method_exists($this,$setter))
$this->$setter(null);
else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
unset($this->_e[strtolower($name)]);
else if(method_exists($this,'get'.$name))
throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
array('{class}'=>get_class($this), '{property}'=>$name)));
}
/**
* PHP magic method
* CComponent未定义的类方法,寻找行为类里的同名方法,实现行为方法的调用
*/
public function __call($name,$parameters)
{
// 行为类存放的$_m数组不空
if($this->_m!==null)
{
// 循环取出$_m数组里存放的行为类
foreach($this->_m as $object)
{
// 行为类对象有效,并且方法存在,调用之
if($object->enabled && method_exists($object,$name))
return call_user_func_array(array($object,$name),$parameters);
}
}
throw new CException(Yii::t('yii','{class} does not have a method named "{name}".',
array('{class}'=>get_class($this), '{name}'=>$name)));
}
/**
* 根据行为名返回行为类对象
*/
public function asa($behavior)
{
return isset($this->_m[$behavior]) ? $this->_m[$behavior] : null;
}
/**
* Attaches a list of behaviors to the component.
* Each behavior is indexed by its name and should be an instance of
* IBehavior}, a string specifying the behavior class, or an
* array of the following structure:
* <pre>
* array(
* 'class'=>'path.to.BehaviorClass',
* 'property1'=>'value1',
* 'property2'=>'value2',
* )
* </pre>
* @param array list of behaviors to be attached to the component
* @since 1.0.2
*/
public function attachBehaviors($behaviors)
{
// $behaviors为数组 $name=>$behavior
foreach($behaviors as $name=>$behavior)
$this->attachBehavior($name,$behavior);
} /**
* 添加一个行为到组件
*/
public function attachBehavior($name,$behavior)
{
/* $behavior不是IBehavior接口的实例,则为
* array(
* 'class'=>'path.to.BehaviorClass',
* 'property1'=>'value1',
* 'property2'=>'value2',
* )
* 传递给Yii::createComponent创建行为了并初始化对象属性
*/
if(!($behavior instanceof IBehavior))
$behavior=Yii::createComponent($behavior);
$behavior->setEnabled(true);
$behavior->attach($this);
return $this->_m[$name]=$behavior;
}
/**
* Raises an event.
* This method represents the happening of an event. It invokes
* all attached handlers for the event.
* @param string the event name
* @param CEvent the event parameter
* @throws CException if the event is undefined or an event handler is invalid.
*/
public function raiseEvent($name,$event)
{
$name=strtolower($name);
// _e[$name] 事件处理句柄队列存在
if(isset($this->_e[$name]))
{
// 循环取出事件处理句柄
foreach($this->_e[$name] as $handler)
{
// 事件处理句柄为全局函数
if(is_string($handler))
call_user_func($handler,$event);
else if(is_callable($handler,true))
{
// an array: 0 - object, 1 - method name
list($object,$method)=$handler;
if(is_string($object)) // 静态类方法
call_user_func($handler,$event);
else if(method_exists($object,$method))
$object->$method($event);
else
throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));
}
else
throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));
// $event 的handled 设置为true后停止队列里剩余句柄的调用
if(($event instanceof CEvent) && $event->handled)
return;
}
}
else if(YII_DEBUG && !$this->hasEvent($name))
throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
array('{class}'=>get_class($this), '{event}'=>$name)));
}
}
Yii PHP 框架分析(二)的更多相关文章
- Yii PHP 框架分析 (一)
Yii PHP 框架分析 (一)作者:wdy http://hi.baidu.com/delphiss/blog/item/f7da86d787adb72506088b4b.html 基于yii1.0 ...
- Yii PHP 框架分析(四)
作者:wdy http://hi.baidu.com/delphiss/blog/item/c15b314f05f9dfc0d0c86a26.html Yii应用的入口脚本最后一句启动了WebAppl ...
- Yii PHP 框架分析(三)
作者:wdy http://hi.baidu.com/delphiss/blog/item/357663d152c0aa85a1ec9c44.html Yii应用的入口脚本引用出了Yii类,Yii类的 ...
- PHP 面向对象及Mediawiki 框架分析(二)
mediaHandler可以理解为处理media文件的 /includes/filerepo/file/File.php /** * Get a MediaHandler instance for t ...
- Android系统--Binder系统具体框架分析(二)Binder驱动情景分析
Android系统--Binder系统具体框架分析(二)Binder驱动情景分析 1. Binder驱动情景分析 1.1 进程间通信三要素 源 目的:handle表示"服务",即向 ...
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- uart驱动框架分析(二)uart_add_one_port
作者:lizuobin (百问网论坛答疑助手) 原文: https://blog.csdn.net/lizuobin2/article/details/51801183 (所用开发板:mini2440 ...
- sobel算法的Soc FPGA实现之框架分析(二)
重点分析一.AXI_VDMA_1 之前一直认为这个就是内含有DDR的ip核(......最近才搞懂是个啥),后来经过对FDMA的分析发现这就是个框架,通AXI总线挂载到bus总线,可以实现PL端FPG ...
- 【原创】Linux PCI驱动框架分析(二)
背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...
随机推荐
- u-boot和linux的机器码
先看u-boot的机器码和linux的机器码是在什么地方决定的. 1. u-boot的机器码是在u-boot的board/fs2410/fs2410.c文件里决定的: /* arch numb ...
- jquery 中的 $("#id") 与 document.getElementById("id") 的区别
以前没注意过,认为jquery 中的 $("#air") 与 document.getElementById("air") 是一回事,指的是同一个东西.在今天写 ...
- e.target与事件委托简例
target定义: target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素.文档或窗口. 语法: event.target event.target.nodeName // ...
- mac 生成支付宝的rsa公钥和私钥 php版本
openssl genrsa -out rsa_private_key.pem 1024 公钥 openssl rsa -in rsa_private_key.pem -pubout -out rsa ...
- Python之路----数据类型
Python的集成开发环境(IDE):pycharm 数据类型 数字 整数int(integer) 浮点数float 布尔型,只有两个值 真:True 假:False 字符串 列表 元组 字典 一.字 ...
- Python Tips and Traps(一)
1.如果想得到一个列表的index和内容,可以通过enumerate快速实现 drinks = ['coffee','tea', 'milk', 'water'] for index, drink i ...
- C# ADO.NET操作数据库 SqlHelp.cs类
刚开始练习ADONET的时候,练习的一个SQLHelp.cs 数据库操作类,很简单,但是也很实用 using System; using System.Collections.Generic; us ...
- 学习TextKit框架(上)
TextKit简介 在iOS7之前我们要实现图文混排要使用CoreText,iOS6时有了Attribute string 可以解决一些简单的富文本需求.直到iOS7 苹果推出了TextKit,Tex ...
- 转:浅谈命令查询职责分离(CQRS)模式
原文来自于:http://www.cnblogs.com/yangecnu/p/Introduction-CQRS.html 在常用的三层架构中,通常都是通过数据访问层来修改或者查询数据,一般修改和查 ...
- Hbase案例分析(一)
Hbase应用场景: 1 随机读或者写 2 大数据上的高并发操作,比如每秒对PB级数据进行上千次操作.(查询,删除等操作) 3 读写均是非常简单的操作,比如没有join操作 Hbase Schema设 ...