Yii的组件机制

组件机制,是Yii整个体系的思想精髓,在使用Yii之前,最应该先了解其组件机制,如果不了解这个机制,那么阅读Yii源代码会非常吃力。组件机制给Yii框架赋予了无穷的灵活性和可扩展性,可以毫不夸张地说,Yii框架的基础结构就是组件。大到CApplication对象、控制器、路由管理器(urlManager),小到一些其它插件,均是以组件形式存在的。

什么是Yii组件?

Yii中几乎所有可实例化并继承自CComponent的类,均可称为组件。

组件的特点是什么?

继承自CComponent类(直接继承或间接继承),拥有事件及行为机制,可在配置文件中定义其各个属性。

如何创建一个组件?

编写自定义类,并继承自CComponent类即可。

CComponent类是所有组件的基类,这个类在Yii框架中至关重要。具体来说,这个类主要实现以下三大功能:

1. 通过利用php的魔术方法__set, __get实现定义类的属性。也就是说一个组件的属性除了使用已经定义过的public成员属性,还可以利用CComponent实现的功能,通过扩展setXXX, getXXX方法扩展属性的设置和获取,对一些特殊的属性,我们可能希望在设置它之时就验证其是格式正确,此时就比较有用。
class webpage extends CComponent {

public $title;

private $_url;

public function setUrl($value='') {

if(is_url($value)){

$this->_url = $value;

}

}

public function getUrl() {

return $this->_url ;

}

}

$page = new webpage();

$page->title = "page title";

$page->url = "/index.php";  # call $page->seturl("/index.php");

echo $page->url   #$page->geturl();

也就是说,如果一个组件定义了setXXX, getXXX,那么就可以在类外部使用普通的属性访问形式。

2. 同样利用setter, getter实现事件处理接口绑定。事件机制在Yii中也是无处不大,Yii使用大量的事件机制来实现组件之间的功能调用(观察者模式)。

那么,如何给组件定义一个事件呢?Yii规定onXX形式的方法,即称为事件,如以下定义:
class form extends CComponent {

public function onSubmit($event) {

$this->raiseEvent('onSubmit',  $event);

}

}

使用以上固定代码,就给car组件创建了一个onStop事件。但是绑定事件究竟有何用处呢? 绑定事件的作用就是当组件产生一系列事件时,将自己的事件通过事件处理器,通知到绑定的各个对象上。例如我们希望当表单提交的时候,将此事件通知给日志组件让其记录之。

$form = new form();

$form ->attachEventHandler( 'onSubmit',  array($logOjbect, "saveLog") );

$form->data = $_POST;

$form->onSubmit( new CEvent($form, array('data'=>$_POST) ) ); #激活事件执行,并调用事件处理接口logObject::saveLog

而logObject的代码可能如下:
class logObject {

public function saveLog($event) {

$event->sender === $form;

$event->params ;

}

}

显然这种方式远比传统方式调用更灵活,概念方式上也更先进一些。

另外,可以使用setter方法绑定事件:

$form->onSubmit = array($logOjbect, "saveLog") ;

注意:form类并未定义onSubmit成员属性。

同时,Yii实现了同一个事件绑定多个处理接口的机制,类似JavaScript中的addEventListener。

事件处理器接口柳芽,以php的callback类型格式为标准,详情参阅以下内容:http://php.net/manual/en/language.types.callable.php

如Yii的CLogRouter::init()中的代码:
Yii::app()->attachEventHandler('onEndRequest',array($this,'processLogs'));

当然也可以写成Yii::app()->onEndRequest = array($this,'processLogs');

而CApplication中定义了onEndRequest事件:
public function onEndRequest($event){

if(!$this->_ended){

$this->_ended=true;

$this->raiseEvent('onEndRequest',$event);

}

}

定义了事件,并给事件绑定了处理器还不够,还得在合适的地方激活事件,如CApplication::run()方法中的逻辑:

public function run(){

if($this->hasEventHandler('onBeginRequest'))

$this->onBeginRequest(new CEvent($this));

$this->processRequest();

if($this->hasEventHandler('onEndRequest'))

$this->onEndRequest(new CEvent($this));

}

也就说,要实现组件的事件机制,需要定义事件,绑定事件处理接口,激活事件。

行为机制

yii的行为机制,可以简单地认为就是一个组件将其它对象的方法或属性直接拿来使用(就如php 5.4引入的trait结构,与行为作用就类似)

trait SayWorld {

public function sayHello() {

echo 'hello world!';

}

}

class MyHelloWorld extends Base {

use SayWorld;

}

$o = new MyHelloWorld();

$o->sayHello();

输出 hello world!

一个行为,就是一个特殊的类,其定义了各种事件及其处理流程,我们先定义一个行为类,包含事件及其对应的方法。

class MyAppBehavior extends CBehavior {

public $status = "app behavior ended.";

public function events() {

return array(

'onEndRequest' => 'appEnd',  #指定组件的onEndRequest事件发生后,调用行为的appEnd

);

}

public function appEnd($event = null) {

echo get_class($this);

}

}

$app->attachBehavior('myapp','MyAppBehavior');

$app->run();

echo $app->status ;

我们发现行为的方法及属性,都是可以被组件直接使用的。

另外一个常见的例子,我们经常要对用户输入的内容进行过滤处理,比如防止其输入html标签,这种情况下,我们也可以考虑使用行为机制处理之。

$form = new FormModel;

If($_POST) {

$form->attributes = $_POST ;

$form->attachBehavior('myFilter', array(

'class' => '',

'strip_tags' => true ,

));

$form->filter(new CEvent($form) ) ;

}

class myHtmlFilter extends CBehavior {

public $strip_tags = false ;

public function events() {

return array(

'filter' => 'filterHtml',

);

}

public function filterHtml($event) {

if($event->sender instanceof CFormModel) {

$input = $event->sender->attributes ;

$event->sender->attributes = $this->filter($input);

}

}

public function filter(&$data) {

return is_array($data)?array_map(array($this, 'filter'),$data):strip_tags($data);

}

}

经过以上例子,可以发现行为方法可以以组件普通方法直接运行。行为有何用处,我目前还没有完全体会到其优势。

<!--EndFragment-->

(转自:http://zhangxugg-163-com.iteye.com/blog/1673325)

yii的个人简单理解
组件:Yii中几乎所有可实例化并继承自CComponent的类,均可称为组件。
事件:类方法,供组件之间调用 已on开头作为标识
行为:特殊的类,供组件直接拿来使用,类似trait特性

(转)Yii的组件机制之一:组件基础类CComponent分析的更多相关文章

  1. 定时组件quartz系列<三>quartz调度机制调研及源码分析

    quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...

  2. Yii Framework 开发教程Zii组件-Tabs示例

    有关Yii Tab类: http://www.yiichina.com/api/CTabView http://www.yiichina.com/api/CJuiTabs http://blog.cs ...

  3. vue 基础-->进阶 教程(3):组件嵌套、组件之间的通信、路由机制

    前面的nodejs教程并没有停止更新,因为node项目需要用vue来实现界面部分,所以先插入一个vue教程,以免不会的同学不能很好的完成项目. 本教程,将从零开始,教给大家vue的基础.高级操作.组件 ...

  4. 谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo

    前言 前端已经过了单兵作战的时代了,现在一个稍微复杂一点的项目都需要几个人协同开发,一个战略级别的APP的话分工会更细,比如携程: 携程app = 机票频道 + 酒店频道 + 旅游频道 + ..... ...

  5. JS组件系列——表格组件神器:bootstrap table(三:终结篇,最后的干货福利)

    前言:前面介绍了两篇关于bootstrap table的基础用法,这章我们继续来看看它比较常用的一些功能,来个终结篇吧,毛爷爷告诉我们做事要有始有终~~bootstrap table这东西要想所有功能 ...

  6. DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  7. Vue系列之 => 父组件向子组件传值

    父组件向子组件传递数据 1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta c ...

  8. vue-父组件向子组件传递方法

    1.父组件向子组件传递方法,使用的是事件绑定机制 v-on:传递给子组件的方法名=“父组件中的方法”

  9. Android组件系列----Activity组件详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

随机推荐

  1. javaweb——Servlet作为控制器

    1.文件预览 JSP:login.jsp--用户登陆,jsp只是用于向客户端展示信息,处理信息的是servlet. welcome.jsp--用户登陆成功,显示给用户的界面. jsp文件是位于webC ...

  2. ahjesus配置vsftpd虚拟用户在Ubuntu

    网上搜索了很多资料,过时,不全,货不对版 已下步骤亲测有效,不包含匿名用户登录 1.新建/home/loguser.txt 并填充内容,格式如下 用户名密码用户名密码用户名密码 2.生成db文件用于用 ...

  3. Gulp-前端进阶A-1

    毕业到转行以来有一年时间了,成为一名程序猿也有大半年了,之前在新浪上随便写写简单的学习过程,感觉不够像那么回事,现在接触前端也有一段时间了,也做过几个项目,认识到可以拓展的实在太多了,希望从这里起步, ...

  4. Python学习01 Hello World

    Python学习之Hello World 准备工作 去官网http://www.python.org/ 下载python的安装包: http://www.python.org/download/ 当前 ...

  5. Android时区及语言代码

    1. 设置默认时区   PRODUCT_PROPERTY_OVERRIDES += \         persist.sys.timezone=Asia/Shanghai\ 注:搜索“persist ...

  6. 【代码笔记】iOS-轮询弹出框

    一,效果图. 二,工程图. 三,代码. RootViewController.m #import "RootViewController.h" //加入弹出框的头文件 #impor ...

  7. NSoperation用法详解及与GCD的比较

    NSInvocationOperation // 基于一个对象和selector来创建操作.如果你已经有现有的方法来执行需要的任务,就可以使用这个类 NSInvocationOperation * o ...

  8. iOS 学习 - 10下载(1) NSURLConnection 篇

    程序的实现需要借助几个对象: NSURLRequest:建立了一个请求,可以指定缓存策略.超时时间.和NSURLRequest对应的还有一个NSMutableURLRequest,如果请求定义为NSM ...

  9. rabbitmq_management 安装失败

    安装rabbitmq_management的时候出现错误 不能连接rabbit,所以查看状态 看意思感觉好像是rabbit没有运行,但是安装的时候都是默认安装的,所以安装完以后服务的名字就是Rabbi ...

  10. 如何退出调起多个Activity的Application?

    1.记录打开的Activity 每打开一个activity,即记录下来,需要关闭时,关闭每一个activity即可. 2.发送特定的广播 在需要结束应用时,发送一个特定广播,每个activity收到此 ...