(转)Yii的组件机制之一:组件基础类CComponent分析

8/31/2015来源:PHP技巧人气:608

(转)Yii的组件机制之一:组件基础类CComponent分析Yii的组件机制

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

什么是Yii组件?

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

组件的特点是什么?

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

如何创建一个组件?

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

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

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

public$title;

PRivate$_url;

publicfunctionsetUrl($value=''){

if(is_url($value)){

$this->_url=$value;

}

}

publicfunctiongetUrl(){

return$this->_url;

}

}

$page=newwebpage();

$page->title="pagetitle";

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

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

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

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

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

publicfunctiononSubmit($event){

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

}

}

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

$form=newform();

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

$form->data=$_POST;

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

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

publicfunctionsaveLog($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事件:publicfunctiononEndRequest($event){

if(!$this->_ended){

$this->_ended=true;

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

}

}

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

publicfunctionrun(){

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

$this->onBeginRequest(newCEvent($this));

$this->processRequest();