(转)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方法扩展属性的设置和获取,对一些特殊的属性,我们可能希望在设置它之时就验证其是格式正确,此时就比较有用。
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分析,布布扣,bubuko.com

时间: 2024-10-22 00:55:49

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

定时组件quartz系列&lt;三&gt;quartz调度机制调研及源码分析

quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的java任务调度框架,功能强大配置灵活.在企业应用中占重要地位.quratz在集群环境中的使用方式是每个企业级系统都要考虑的问题.早在2006年,在ITeye上就有一篇关于quratz集群方案的讨论:http://www.iteye.com/topic/40970 ITeye创始人@Robbin在8楼

Yii的缓存机制之片段缓存

一.首先在main.php配置缓存组件 在components里面添加cache项.代码如下: // application components 'components'=>array( 'user'=>array( // enable cookie-based authentication 'allowAutoLogin'=>true, ), 'db'=>array( 'connectionString' => 'mysql:host=localhost;dbname=y

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

前言:前面介绍了两篇关于bootstrap table的基础用法,这章我们继续来看看它比较常用的一些功能,来个终结篇吧,毛爷爷告诉我们做事要有始有终~~bootstrap table这东西要想所有功能覆盖似乎不太现实,博主挑选了一些自认为比较常用的功能在此分享给各位园友.源码也在这篇统一给出.好了,不多说废话,开始我们的干货之旅吧. bootstrap table系列: JS组件系列——表格组件神器:bootstrap table JS组件系列——表格组件神器:bootstrap table(二

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

前言 前端已经过了单兵作战的时代了,现在一个稍微复杂一点的项目都需要几个人协同开发,一个战略级别的APP的话分工会更细,比如携程: 携程app = 机票频道 + 酒店频道 + 旅游频道 + ...... 每个频道有独立的团队去维护这些代码,具体到某一个频道的话有会由数十个不等的页面组成,在各个页面开发过程中,会产生很多重复的功能,比如弹出层提示框,像这种纯粹非业务的UI,便成了我们所谓的UI组件,最初的前端组件也就仅仅指的是UI组件. 而由于移动端的兴起,前端页面的逻辑已经变得很重了,一个页面的

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

[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3924567.html 联系方式:[email protected] [正文] 注:四大组件指的是应用组件:Activity.Service.BroadcastReceiver.ContentProvider:之前的控件指的是UI组件. 博文目录: 一.Activity简介 二.Activity的状

tomcat(14)服务器组件和服务组件

[0]README 0.1)本文部分文字描述转自 "how tomcat works",旨在学习 "tomcat(14)服务器组件和服务组件" 的基础知识: 0.2)for complete source code ,please visit  https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter14 [1]服务器组件(org.apache.catalina.Server) 1)org.a

vue的$emit 与$on父子组件与兄弟组件的之间通信

本文主要对vue 用$emit 与 $on 来进行组件之间的数据传输. 主要的传输方式有三种: 1.父组件到子组件通信 2.子组件到父组件的通信 3.兄弟组件之间的通信 一.父组件传值给子组件 父组件给子组件传子,使用props //父组件:parent.vue <template> <div> <child :vals = "msg"></child> </div> </template> <script&

Tomcat中的服务器组件和 服务组件

开始学习Tocmat时,都是学习如何通过实例化一个连接器 和 容器 来获得一个Servlet容器,并将连接器  和 servlet容器相互关联,但是之前学习的都只有一个连接器可以使用,该连接器服务8080端口上的HTTP请求,无法添加另一个连接器来服务 诸如 HTTPS之类的其他请求,而且前面所有学的示例,都缺少一种启动或者 关闭servlet容器的机制,那么下面学习一下提供这两种机制的特性的组件,分别是服务器组件 和 服务组件. 服务器组件. org.apahce.catalina.Serve

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

本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分页组件 七 xxx 八 xxx 一 认证组件 1. 局部认证组件 我们知道,我们不管路由怎么写的,对应的视图类怎么写的,都会走到dispatch方法,进行分发, 在咱们看的APIView类中的dispatch方法的源码中,有个self.initial(request, *args, **kwargs),那么认证.权限.频率这三个默认组件都在这个方法里面了,如果我们自己没有做这三个组件的配置,那么会使用源码中默