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);
}
}
经过以上例子,可以发现行为方法可以以组件普通方法直接运行。行为有何用处,我目前还没有完全体会到其优势。
相关推荐
框架的每个组件都是一个类,这些类通常继承自Yii的基类,例如CComponent或CModule。CComponent是所有自定义组件的基础,它提供了事件和属性的机制。CModule代表了一个模块,它是可独立部署和复用的代码单元,可以...
2. **组件系统**:Yii的组件化设计允许开发者复用代码和配置,`CComponent`是所有组件的基类,源码中的许多类都是其子类,如`CWebApplication`和`CController`。 3. **数据库操作**:Yii的`CDbConnection`和`...
例如,组件的命名需要清晰描述其功能,文件结构需要符合Yii的标准目录结构,组件类的定义需要遵循CComponent类的继承规则。此外,组件在应用启动时被加载,在应用关闭时卸载,这些都是开发者在编写扩展组件时需要...
- **组件与对象**:Yii 2.0 将原有的 `CComponent` 类拆分为两个类:`yii\base\Object` 和 `yii\base\Component`。前者作为轻量级基类,支持通过 getters 和 setters 方法定义属性;后者继承自 `Object` 类,增加了...
`CComponent`是Yii中所有组件的基础类,它提供了事件管理和行为(Behaviors)的功能。`raiseEvent`方法是负责触发事件的核心方法,它会遍历并执行与事件相关的所有句柄。 6. **事件处理的顺序**: 事件句柄的执行...
- **组件(Component)与对象(Object)**:2.0版本中,原本的`CComponent`类被拆分为`yii\base\Object`和`yii\base\Component`两个独立的基类。`Object`类提供了基本的对象生命周期管理功能,而`Component`类则在此...
`CComponent`是大多数Yii类的基类,它提供了组件的基础实现。通过PHP的魔术方法`__get()`和`__set()`,我们可以方便地访问和修改组件的属性,即使这些属性是受保护或私有的。 1. `__get()`方法:当尝试访问一个不...
在Yii中,CComponent类是许多其他类的基础,它提供了三个关键特性:成员变量扩展、事件模型和行为类绑定。 1. 成员变量扩展: 这个特性允许开发者通过定义`getXXX()`和`setXXX()`方法来扩展类的成员变量,而不是...
- **base**:基础类,提供基本的类定义,如CApplication、CComponent等。 - **db**:数据库相关的组件,如CDbConnection、CDbCommand等。 - **web**:Web应用程序相关的类,如CController、CView等。 - **...
CComponent是Yii中所有组件的基础类,它具有内置的事件处理机制。通过CComponent的__set()方法,开发者可以绑定事件处理器到一个事件上。当事件被触发时,它会依次调用绑定的所有处理器。 以下为Yii Framework中...