YII框架分析笔记2:组件和事件行为管理

Yii是一个基于组件、用于开发大型 Web 应用的高性能 PHP 框架。CComponent几乎是所有类的基类,它控制着组件与事件的管理,其方法与属性如下,私有变量$_e数据存放事件(evnet,有些地方叫 hook),$_m数组存放行为(behavior)。


组件管理

YII是一个纯oop框架,很多类中的成员变量的受保护或者私有的,CComponent中利用php中的魔术方法__get(),__set()来访问和设置属性,但这些方法的作用远不指这些。下面用__get()来说明

[php] view plaincopy

  1. public function __get($name)
  2. {
  3. $getter=‘get‘.$name;
  4. if(method_exists($this,$getter))
  5. return $this->$getter();
  6. else if(strncasecmp($name,‘on‘,2)===0 && method_exists($this,$name))
  7. {
  8. // duplicating getEventHandlers() here for performance
  9. $name=strtolower($name);
  10. if(!isset($this->_e[$name]))
  11. $this->_e[$name]=new CList;
  12. return $this->_e[$name];
  13. }
  14. else if(isset($this->_m[$name]))
  15. return $this->_m[$name];
  16. else if(is_array($this->_m))
  17. {
  18. foreach($this->_m as $object)
  19. {
  20. if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name)))
  21. return $object->$name;
  22. }
  23. }
  24. throw new CException(Yii::t(‘yii‘,‘Property "{class}.{property}" is not defined.‘,
  25. array(‘{class}‘=>get_class($this), ‘{property}‘=>$name)));
  26. }

当CComponent或者其子类对象实例$obj->name的时候,__get($name)方法:
1、首先判断实例中是否有getName()方法,如果有则返回 ,如果没有执行第2步
2、判断是否是以on开头的,以on开头的一般都是CComponent子类中预留的事件,用与挂在事件,通过method_exists($this,$name)判断该name是否存在类的实例中,如果存在,返回事件,否则执行第3步
3、如果name存在行为数组中,返回改行为,如果不存在,执行第4步
4、遍历行为数组,数组中行为是CBehavior子类的实例,而CBehavior又是CComponent中子类,所以用递归的方法获取行为中的方法,如果没有,执行第5步
5、抛出异常:请求的属性不存在。

在CComponent子类中可以重载__get()方法,如在CModule中加入了获取组件的判断。这就注意一个问题了属性和组件名最好不要重名,因为程序会优先加载组件,可能得到的不是我们想要的属性,如果必须重名的话,就要用getter获取属性。

[php] view plaincopy

  1. public function __get($name)
  2. {
  3. if($this->hasComponent($name))
  4. return $this->getComponent($name);
  5. else
  6. return parent::__get($name);
  7. }

关于组件的加载与创建,上篇YII框架分析笔记1:YII执行流程
的第3点中有个疑问:注册框架核心组件的时候一下子加载这么多,是不是影响性能呢?其实没有,注册的时候只是把组件和其对应的配置用键值对的形式保存在数
组中(预加载的除外),当用到时候才像上面那样去创建组件,会通过YIIBase中的createComponent()方法创建,并初始化。通过
CModule或其子孙类(如CWebApplication)调用__get()或getComponent()获取组件时,CModule通
过$_components数组建立对象池,确保每个组件在一次请求中只实例化一次。


事件行为管理

事件相当于对一个组件的扩展或者插件,以组件中预留的钩子实现组件内部调
用外部、外部对组件部分控制。在CComponent子类中可以定义以on开头的方法为事件,类似于js中的onclick、onchange等,其实原
理差不多。所有事件是与CComponent在同一文件中CEvent的子类。

[php] view plaincopy

  1. /**
  2. * Raised right BEFORE the application processes the request.
  3. * @param CEvent $event the event parameter
  4. */
  5. public function onBeginRequest($event)
  6. {
  7. $this->raiseEvent(‘onBeginRequest‘,$event);
  8. }
  9. /**
  10. * Runs the application.
  11. * This method loads static application components. Derived classes usually overrides this
  12. * method to do more application-specific tasks.
  13. * Remember to call the parent implementation so that static application components are loaded.
  14. */
  15. public function run()
  16. {
  17. if($this->hasEventHandler(‘onBeginRequest‘))
  18. $this->onBeginRequest(new CEvent($this));
  19. $this->processRequest();
  20. if($this->hasEventHandler(‘onEndRequest‘))
  21. $this->onEndRequest(new CEvent($this));
  22. }

比如在CApplication中调用run()方法在处理请求之前先判断外部是否传人onBeginRequest事件的句柄,如果有则通过
onBeginRequest($event)方法调用CComponent中的raiseEvent()方法执行句柄中的函数或者方法。

行为是事件的升级版,所有的行为都是CBehavior的子类。分析上面的__get()方法分析第4步可以看出来行为的作用是完全扩展组件的特性,可以是属性、方法、事件甚至行为,这样使程序开发更加灵活。

行为的另一个作用是将相似事件句柄放在一起,在行为执行attach()
方法的时候会将events()方法中返回的事件句柄绑定,这样做达到方面管理和扩展的目的。比如CModelBehavior中将model相关的事件
集中起来,便于其子类的复用,当我们需求为model添加行为的时候可以继承它。

时间: 2024-11-08 17:23:50

YII框架分析笔记2:组件和事件行为管理的相关文章

YII框架分析笔记10:日志

yii框架中日志组件记录的等级5类,在CLogger已通过常量定义: const LEVEL_TRACE='trace'; const LEVEL_WARNING='warning'; const LEVEL_ERROR='error'; const LEVEL_INFO='info'; const LEVEL_PROFILE='profile'; CLogger为所有日志写入和获取提供接口,通过日志路由管理类CLogRouter将日志分发到不同日志展现或存储介质中. 日志组件配置 [php]

YII框架分析笔记1:YII执行流程

yii整体执行流程直观,具体由以下步骤: 1.程序入口文件index.php加载yii框架引导程序(bootstrap)文件yii.php,加载配置文件以及其他自定义配置. 2.yii.php中Yii类继承了YiiBase,主要封装框架的一些通用方法,比如自动加载.创建组件.核心类路径映射.记录日志以及调试等,YiiBase.php中注册自动加载方法.另外Yii类预留可以自定义一些方法作为扩展. 3.回到index.php,Yii::createWebApplication($config),创

YII框架分析笔记6:视图

YII框架使用的view是在原生的php模板上进行扩展的.CController中对视图的渲染有多种方法: render($view,$data=null,$return=false)//连同layout一起渲染 renderPartial($view,$data=null,$return=false,$processOutput=false)//不渲染layout renderText($text,$return=false)//渲染静态内容和layout renderDynamic($cal

YII框架分析笔记3:表单模型和验证

表单模型CFormModel绝大部分继承CModelCModel,由于表模型数据不需要持久化,所以主要在验证操作上.下面以框架脚手架生成的网站登录为例说明表单模型. [php] view plaincopy //模型中的验证规则 public function rules() { return array( array('username, password', 'required'), array('rememberMe', 'boolean'), array('password', 'aut

YII框架分析笔记8:CDataProvider

CDataProvider,顾名思义,数据提供者,它提供了三个抽象方法(fetchData,.fetchKeys 和 calculateTotalItemCount),分别为调用不同数据结构的数据提供了获取数据.获取键值.获取数量的,接口,在YII框架 中,CActiveDataProvider.CArrayDataProvider.CSqlDataProvider是它的子类,除了提供数据之外, 他还提供分页和排序功能.下面以获取数据fetchData()为例 CActiveDataProvid

YII框架分析笔记5:控制器和动作

CBaseController是控制器和挂件的基类,主要提供了视图渲染,挂件,剪辑.片段缓存等方法,CController是所有应用中自定义控制器的基类. 创建动作 [php] view plaincopy public function run($actionID) { if(($action=$this->createAction($actionID))!==null) { if(($parent=$this->getModule())===null) $parent=Yii::app()

YII框架分析笔记4:ar模型和db

YII中实现两种类型的模型,分别是表单模型和活动记录.在持久化数据方面,YII只实现了活动记录,对于复杂的数据关系可以用框架提供的DAO来自己写model,对应集成doctrine这样的ORM还没有仔细研究过. ar模型 框架中的model是CModel子类,CModel主要是一些验证与错误处理,并实现迭代器和数组访问接口,活动记录模型CActiveRecord是AR模型的基类. 每个AR类代表一个单独的数据表,一个AR实例则代表那个表中的一行.AR是一种对象关系映射(ORM)的设计模式,它负责

YII框架分析笔记9:url路由

以创建url路由为例,从CWebApplication执行请求过程说起,如果在配置中设置了catchAllRequest,所有请求将会定位到配置中的路由中,否则的需要CUrlManager的parseUrl()方法解析解析url获取路由. [php] view plaincopy /** * Parses the user request. * @param CHttpRequest $request the request application component * @return str

YII框架分析笔记12:主题管理

YII主题的控制由CThemeManager和CTheme管理,CThemeManager在应用初始化时作为核心组件注册,主题默认路径是app/themes/. 主题配置 由于主题组件在应用初始化时注册,其配置以及很方面,比如在app/themes/下有一个custom1主题 在主配置文件中加入'theme'=>'custom1'键值对,在主题注册的时候会调用 CWebApplication::setTheme($value)初始化主题的名字. 获取主题 主题的获取从控制器渲染视图说起,通过视a