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源码分析

//所有部件的基类

  1. class CComponent
  2. {
  3. private $_e;
  4. private $_m;
  5. //获取部件属性、事件和行为的magic method
  6. public function __get($name)
  7. {
  8. $getter='get'.$name;
  9. //是否存在属性的get方法
  10. if(method_exists($this,$getter))
  11. return $this->$getter();
  12. //以on开头,获取事件处理句柄
  13. else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
  14. {
  15. // 事件名小写
  16. $name=strtolower($name);
  17. // 如果_e[$name] 不存在,返回一个空的CList事件句柄队列对象
  18. if(!isset($this->_e[$name]))
  19. $this->_e[$name]=new CList;
  20. // 返回_e[$name]里存放的句柄队列对象
  21. return $this->_e[$name];
  22. }
  23. // _m[$name] 里存放着行为对象则返回
  24. else if(isset($this->_m[$name]))
  25. return $this->_m[$name];
  26. else
  27. throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
  28. array('{class}'=>get_class($this), '{property}'=>$name)));
  29. }
  30. /**
  31. * PHP magic method
  32. * 设置组件的属性和事件
  33. */
  34. public function __set($name,$value)
  35. {
  36. $setter='set'.$name;
  37. //是否存在属性的set方法
  38. if(method_exists($this,$setter))
  39. $this->$setter($value);
  40. //name以on开头,这是事件处理句柄
  41. else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
  42. {
  43. // 事件名小写
  44. $name=strtolower($name);
  45. // _e[$name] 不存在则创建一个CList对象
  46. if(!isset($this->_e[$name]))
  47. $this->_e[$name]=new CList;
  48. // 添加事件处理句柄
  49. $this->_e[$name]->add($value);
  50. }
  51. // 属性没有set方法,只有get方法,为只读属性,抛出异常
  52. else if(method_exists($this,'get'.$name))
  53. throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
  54. array('{class}'=>get_class($this), '{property}'=>$name)));
  55. else
  56. throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
  57. array('{class}'=>get_class($this), '{property}'=>$name)));
  58. }
  59. /**
  60. * PHP magic method
  61. * 为isset()函数提供是否存在属性和事件处理句柄的判断
  62. */
  63. public function __isset($name)
  64. {
  65. $getter='get'.$name;
  66. if(method_exists($this,$getter))
  67. return $this->$getter()!==null;
  68. else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
  69. {
  70. $name=strtolower($name);
  71. return isset($this->_e[$name]) && $this->_e[$name]->getCount();
  72. }
  73. else
  74. return false;
  75. }
  76. /**
  77. * PHP magic method
  78. * 设置属性值为空或删除事件名字对应的处理句柄
  79. */
  80. public function __unset($name)
  81. {
  82. $setter='set'.$name;
  83. if(method_exists($this,$setter))
  84. $this->$setter(null);
  85. else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
  86. unset($this->_e[strtolower($name)]);
  87. else if(method_exists($this,'get'.$name))
  88. throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
  89. array('{class}'=>get_class($this), '{property}'=>$name)));
  90. }
  91. /**
  92. * PHP magic method
  93. * CComponent未定义的类方法,寻找行为类里的同名方法,实现行为方法的调用
  94. */
  95. public function __call($name,$parameters)
  96. {
  97. // 行为类存放的$_m数组不空
  98. if($this->_m!==null)
  99. {
  100. // 循环取出$_m数组里存放的行为类
  101. foreach($this->_m as $object)
  102. {
  103. // 行为类对象有效,并且方法存在,调用之
  104. if($object->enabled && method_exists($object,$name))
  105. return call_user_func_array(array($object,$name),$parameters);
  106. }
  107. }
  108. throw new CException(Yii::t('yii','{class} does not have a method named "{name}".',
  109. array('{class}'=>get_class($this), '{name}'=>$name)));
  110. }
  111. /**
  112. * 根据行为名返回行为类对象
  113. */
  114. public function asa($behavior)
  115. {
  116. return isset($this->_m[$behavior]) ? $this->_m[$behavior] : null;
  117. }
  118. /**
  119. * Attaches a list of behaviors to the component.
  120. * Each behavior is indexed by its name and should be an instance of
  121. * IBehavior}, a string specifying the behavior class, or an
  122. * array of the following structure:
  123. * <pre>
  124. * array(
  125. * 'class'=>'path.to.BehaviorClass',
  126. * 'property1'=>'value1',
  127. * 'property2'=>'value2',
  128. * )
  129. * </pre>
  130. * @param array list of behaviors to be attached to the component
  131. * @since 1.0.2
  132. */
  133. public function attachBehaviors($behaviors)
  134. {
  135. // $behaviors为数组 $name=>$behavior
  136. foreach($behaviors as $name=>$behavior)
  137. $this->attachBehavior($name,$behavior);
  138. }
  139.  
  140. /**
  141. * 添加一个行为到组件
  142. */
  143. public function attachBehavior($name,$behavior)
  144. {
  145. /* $behavior不是IBehavior接口的实例,则为
  146. * array(
  147. * 'class'=>'path.to.BehaviorClass',
  148. * 'property1'=>'value1',
  149. * 'property2'=>'value2',
  150. * )
  151. * 传递给Yii::createComponent创建行为了并初始化对象属性
  152. */
  153. if(!($behavior instanceof IBehavior))
  154. $behavior=Yii::createComponent($behavior);
  155. $behavior->setEnabled(true);
  156. $behavior->attach($this);
  157. return $this->_m[$name]=$behavior;
  158. }
  159. /**
  160. * Raises an event.
  161. * This method represents the happening of an event. It invokes
  162. * all attached handlers for the event.
  163. * @param string the event name
  164. * @param CEvent the event parameter
  165. * @throws CException if the event is undefined or an event handler is invalid.
  166. */
  167. public function raiseEvent($name,$event)
  168. {
  169. $name=strtolower($name);
  170. // _e[$name] 事件处理句柄队列存在
  171. if(isset($this->_e[$name]))
  172. {
  173. // 循环取出事件处理句柄
  174. foreach($this->_e[$name] as $handler)
  175. {
  176. // 事件处理句柄为全局函数
  177. if(is_string($handler))
  178. call_user_func($handler,$event);
  179. else if(is_callable($handler,true))
  180. {
  181. // an array: 0 - object, 1 - method name
  182. list($object,$method)=$handler;
  183. if(is_string($object)) // 静态类方法
  184. call_user_func($handler,$event);
  185. else if(method_exists($object,$method))
  186. $object->$method($event);
  187. else
  188. throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
  189. array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));
  190. }
  191. else
  192. throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
  193. array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));
  194. // $event 的handled 设置为true后停止队列里剩余句柄的调用
  195. if(($event instanceof CEvent) && $event->handled)
  196. return;
  197. }
  198. }
  199. else if(YII_DEBUG && !$this->hasEvent($name))
  200. throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
  201. array('{class}'=>get_class($this), '{event}'=>$name)));
  202. }
  203. }

Yii PHP 框架分析(二)的更多相关文章

  1. Yii PHP 框架分析 (一)

    Yii PHP 框架分析 (一)作者:wdy http://hi.baidu.com/delphiss/blog/item/f7da86d787adb72506088b4b.html 基于yii1.0 ...

  2. Yii PHP 框架分析(四)

    作者:wdy http://hi.baidu.com/delphiss/blog/item/c15b314f05f9dfc0d0c86a26.html Yii应用的入口脚本最后一句启动了WebAppl ...

  3. Yii PHP 框架分析(三)

    作者:wdy http://hi.baidu.com/delphiss/blog/item/357663d152c0aa85a1ec9c44.html Yii应用的入口脚本引用出了Yii类,Yii类的 ...

  4. PHP 面向对象及Mediawiki 框架分析(二)

    mediaHandler可以理解为处理media文件的 /includes/filerepo/file/File.php /** * Get a MediaHandler instance for t ...

  5. Android系统--Binder系统具体框架分析(二)Binder驱动情景分析

    Android系统--Binder系统具体框架分析(二)Binder驱动情景分析 1. Binder驱动情景分析 1.1 进程间通信三要素 源 目的:handle表示"服务",即向 ...

  6. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  7. uart驱动框架分析(二)uart_add_one_port

    作者:lizuobin (百问网论坛答疑助手) 原文: https://blog.csdn.net/lizuobin2/article/details/51801183 (所用开发板:mini2440 ...

  8. sobel算法的Soc FPGA实现之框架分析(二)

    重点分析一.AXI_VDMA_1 之前一直认为这个就是内含有DDR的ip核(......最近才搞懂是个啥),后来经过对FDMA的分析发现这就是个框架,通AXI总线挂载到bus总线,可以实现PL端FPG ...

  9. 【原创】Linux PCI驱动框架分析(二)

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

随机推荐

  1. oracle创建表(并且实现ID自增)

    CREATE TABLE STUDENT ( ID INT NOT NULL, NAME VARCHAR2(4000) NOT NULL, PRIMARY KEY(ID) ) TABLESPACE M ...

  2. properties文件的继承(套用)关系

    现项目中有多个配置文件分布于/props____def.properties____/env_______def.propertiess_______/dev_______def.properties ...

  3. 【java版坦克大战---准备篇】 java 绘图

    要写坦克大战当然要先画出坦克.java画图是基础. package com.game; import java.awt.*; import javax.swing.*; public class Pr ...

  4. linux中C的静态库和动态库分析

    从开始学C语言写第一个"hello world"历程到现在,我依然困惑于到底这个程序完整的执行流程是什么样的.不过,现在我正在尝试一点一点的揭开它的面纱.现在,我尝试分析linux ...

  5. bss段为什么需要初始化?

    我们都知道bss段需要初始化,但是这是为什么呢? 通过浏览资料,我们都会发现,bss段是不会出现在程序下载文件(*.bin *.hex)中的,因为全都是0.如果把它们出现在程序下载文件中,会增加程序下 ...

  6. 7个热门开源PHP框架

    PHP(Hypertext Preprocessor)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点.虽然有很多其它可供选择的Web开发语言,像:ASP 和Ruby,但是PHP是目 ...

  7. 个人笔记--struts2对Action的权限拦截

    一.编写一个类实现com.opensymphony.xwork2.interceptor.Interceptor 接口 PermissionInterceptor.java <pre name= ...

  8. css3媒体查询判断移动设备横竖屏

    /* 设备竖屏时调用该段css代码 */ @media all and (orientation : portrait){ body{   background-color:blue;  } } /* ...

  9. 修改PHP上传大小设置

    目前文档文库上传大小是读取服务器的PHP环境的设置,你们的PHP环境上传限制是多少,这里显示的就是多少. 很多用户问我如何修改上传大小,自己可以百度一下方法,也可以根据以下步骤修改: 1.找到服务务器 ...

  10. Performance Test of List<T>, LinkedList<T>, Queue<T>, ConcurrentQueue<T>

    //Test Group 1 { var watch = Stopwatch.StartNew(); var list = new List<int>(); ; j < ; j++) ...