Yii框架组件和事件行为管理详解


Posted in PHP onMay 20, 2016

本文实例讲述了Yii框架组件和事件行为管理。分享给大家供大家参考,具体如下:

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

Yii框架组件和事件行为管理详解

组件管理

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

public function __get($name)
{
  $getter='get'.$name;
  if(method_exists($this,$getter))
    return $this->$getter();
  else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
  {
    // duplicating getEventHandlers() here for performance
    $name=strtolower($name);
    if(!isset($this->_e[$name]))
      $this->_e[$name]=new CList;
    return $this->_e[$name];
  }
  else if(isset($this->_m[$name]))
    return $this->_m[$name];
  else if(is_array($this->_m))
  {
    foreach($this->_m as $object)
    {
      if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name)))
        return $object->$name;
    }
  }
  throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
    array('{class}'=>get_class($this), '{property}'=>$name)));
}

当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获取属性。

public function __get($name)
{
  if($this->hasComponent($name))
    return $this->getComponent($name);
  else
    return parent::__get($name);
}

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

事件行为管理

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

/**
* Raised right BEFORE the application processes the request.
* @param CEvent $event the event parameter
*/
public function onBeginRequest($event)
{
  $this->raiseEvent('onBeginRequest',$event);
}
/**
* Runs the application.
* This method loads static application components. Derived classes usually overrides this
* method to do more application-specific tasks.
* Remember to call the parent implementation so that static application components are loaded.
*/
public function run()
{
  if($this->hasEventHandler('onBeginRequest'))
    $this->onBeginRequest(new CEvent($this));
  $this->processRequest();
  if($this->hasEventHandler('onEndRequest'))
    $this->onEndRequest(new CEvent($this));
}

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

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

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

PHP 相关文章推荐
分享自定义的几个PHP功能函数
Apr 15 PHP
PHP实现恶意DDOS攻击避免带宽占用问题方法
May 27 PHP
wampserver改变默认网站目录的办法
Aug 05 PHP
PHP模拟asp中response类实现方法
Aug 08 PHP
PHP使用file_get_content设置头信息的方法
Feb 14 PHP
关于PHP 如何用 curl 读取 HTTP chunked 数据
Feb 26 PHP
[原创]php实现子字符串位置相互对调互换的方法
Jun 02 PHP
图文详解phpstorm配置Xdebug进行调试PHP教程
Jun 13 PHP
PHP 自动加载的简单实现(推荐)
Aug 12 PHP
php版微信自动获取收货地址api用法示例
Sep 22 PHP
DEDE实现转跳属性文档在模板上调用出转跳地址
Nov 04 PHP
Thinkphp5行为使用方法汇总
Dec 21 PHP
Yii框架表单模型和验证用法
May 20 #PHP
ThinkPHP中Common/common.php文件常用函数功能分析
May 20 #PHP
thinkPHP3.x常量整理(预定义常量/路径常量/系统常量)
May 20 #PHP
ThinkPHP表单令牌错误的相关解决方法分析
May 20 #PHP
ThinkPHP使用Ueditor的方法详解
May 20 #PHP
thinkphp3.x中变量的获取和过滤方法详解
May 20 #PHP
thinkphp3.x中session方法的用法分析
May 20 #PHP
You might like
全国FM电台频率大全 - 29 青海省
2020/03/11 无线电
Zend Framework入门知识点小结
2016/03/19 PHP
PHP实现生成数据字典功能示例
2018/05/24 PHP
PHP进阶学习之反射基本概念与用法分析
2019/06/18 PHP
很可爱的输入框
2008/08/03 Javascript
Jquery 设置标题的自动翻转
2009/10/03 Javascript
JQuery插件Style定制化方法的分析与比较
2012/05/03 Javascript
js动态往表格的td中添加图片并注册事件
2014/06/12 Javascript
nodejs 整合kindEditor实现图片上传
2015/02/03 NodeJs
JavaScript给input的value赋值引发的关于基本类型值和引用类型值问题
2015/12/07 Javascript
轻松搞定jQuery.noConflict()
2016/02/15 Javascript
angularjs 中$apply,$digest,$watch详解
2016/10/13 Javascript
JavaScript实现为事件句柄绑定监听函数的方法分析
2017/11/14 Javascript
jquery实现左右轮播切换效果
2018/01/01 jQuery
js构造函数constructor和原型prototype原理与用法实例分析
2020/03/02 Javascript
vant-ui框架的一个bug(解决切换后onload不触发)
2020/11/11 Javascript
Python2.x中文乱码问题解决方法
2015/06/02 Python
python实现定时自动备份文件到其他主机的实例代码
2018/02/23 Python
谈谈Python中的while循环语句
2019/03/10 Python
python批量爬取下载抖音视频
2019/06/17 Python
基于python连接oracle导并出数据文件
2020/04/28 Python
python3 re返回形式总结
2020/11/20 Python
使用HTML5在网页中嵌入音频和视频播放的基本方法
2016/02/22 HTML / CSS
请说出你所知道的线程同步的方法
2013/04/19 面试题
假日旅行社实习自我鉴定
2013/09/24 职场文书
办公室年终个人自我评价
2013/10/28 职场文书
户外拓展活动方案
2014/02/11 职场文书
岗位职责怎么写
2014/03/14 职场文书
食品质量与安全专业毕业生求职信
2014/08/11 职场文书
三八妇女节超市活动方案
2014/08/18 职场文书
2014年挂职干部工作总结
2014/12/06 职场文书
2015年元旦主持词开场白
2014/12/14 职场文书
安全承诺书
2015/01/19 职场文书
农民工工资承诺书大全
2015/05/04 职场文书
python spilt()分隔字符串的实现示例
2021/05/21 Python
项目中Nginx多级代理是如何获取客户端的真实IP地址
2022/05/30 Servers