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 如何向 MySQL 发送数据
Oct 09 PHP
php上传、管理照片示例
Oct 09 PHP
在PHP中实现Javascript的escape()函数代码
Aug 08 PHP
php设计模式 Decorator(装饰模式)
Jun 26 PHP
ThinkPHP3.0略缩图不能保存到子目录的解决方法
Sep 30 PHP
php过滤所有恶意字符(批量过滤post,get敏感数据)
Mar 18 PHP
PHP中比较两个字符串找出第一个不同字符位置例子
Apr 08 PHP
浅谈Eclipse PDT调试PHP程序
Jun 09 PHP
php Imagick获取图片RGB颜色值
Jul 28 PHP
详解PHP发送邮件知识点
May 06 PHP
使用PHPExcel导出Excel表
Sep 08 PHP
PHP连接及操作PostgreSQL数据库的方法详解
Jan 30 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
基于MySQL到MongoDB简易对照表的详解
2013/06/03 PHP
PHP把小数转成整数3种方法
2014/06/30 PHP
Laravel框架文件上传功能实现方法示例
2019/04/16 PHP
小议Function.apply()之二------利用Apply的参数数组化来提高 JavaScript程序性能
2006/11/30 Javascript
jQuery温习篇 强大的JQuery选择器
2010/04/24 Javascript
jQuery对象和DOM对象使用说明
2010/06/25 Javascript
jsp+javascript打造级连菜单的实例代码
2013/06/14 Javascript
js调用图片隐藏&显示实现代码
2013/09/13 Javascript
java与javascript之间json格式数据互转介绍
2013/10/29 Javascript
利用javascript数组长度循环数组内所有元素
2013/12/27 Javascript
JavaScript实现的一个日期格式化函数分享
2014/12/06 Javascript
JavaScript实现数字数组按照倒序排列的方法
2015/04/06 Javascript
jQuery实现可兼容IE6的滚动监听功能
2017/09/20 jQuery
在element-ui的el-tree组件中用render函数生成el-button的实例代码
2018/11/05 Javascript
微信小程序解除10个请求并发限制
2018/12/18 Javascript
微信小程序 点击切换样式scroll-view实现代码实例
2019/10/11 Javascript
js实现单元格拖拽效果
2020/02/10 Javascript
[04:52]第二届DOTA2亚洲邀请赛主赛事第一天比赛集锦:OG娜迦海妖放大配合谜团大中3人
2017/04/02 DOTA
python根据时间生成mongodb的ObjectId的方法
2015/03/13 Python
Python编写百度贴吧的简单爬虫
2015/04/02 Python
编写Python脚本来获取Google搜索结果的示例
2015/05/04 Python
简单介绍Python的Django框架加载模版的方式
2015/07/20 Python
python matplotlib坐标轴设置的方法
2017/12/05 Python
Pyspider中给爬虫伪造随机请求头的实例
2018/05/07 Python
使用Python获取并处理IP的类型及格式方法
2018/11/01 Python
详解python:time模块用法
2019/03/25 Python
印度在线购买电子产品网站:Croma
2020/01/02 全球购物
美国小蜜蜂Burt’s Bees德国官网:天然唇部、皮肤和身体护理产品
2020/06/14 全球购物
德国富尔达运动鞋店:43einhalb
2020/12/25 全球购物
CSS实现fullpage.js全屏滚动效果的示例代码
2021/03/24 HTML / CSS
园林资料员岗位职责
2013/12/30 职场文书
车辆工程专业求职信
2014/04/28 职场文书
2015年小学生暑假总结
2015/07/13 职场文书
少先大队干部竞选稿
2015/11/20 职场文书
互联网创业商业模式以及赚钱法则有哪些?
2019/10/12 职场文书
Redis 的查询很快的原因解析及Redis 如何保证查询的高效
2022/03/16 Redis