`

Yii分析2:组件的事件机制

阅读更多

 

在深入分析 Yii 的运行之前,我们先来看一下 Yii 框架中一个很重要的机制 - 事件。

 

Yii 官方参考文档关于组件事件的解释:

 

=======================================================================

组件事件是一些特殊的属性,它们使用一些称作 事件句柄 event handlers )的方法作为其值。 附加 ( 分配 ) 一个方法到一个事件将会引起方法在事件被唤起处自动被调用。因此, 一个组件的行为可能会被一种在部件开发过程中不可预见的方式修改。

组件事件以 on 开头的命名方式定义。和属性通过 getter/setter 方法来定义的命名方式一样, 事件的名称是大小写不敏感的。以下代码定义了一个 onClicked 事件 :

public function onClicked($event)
{
    $this->raiseEvent('onClicked', $event);
}

 

这里作为事件参数的 $event CEvent 或其子类的实例。

我们可以附加一个方法到此 event ,如下所示 :

$component->onClicked=$callback;

 

这里的 $callback 指向了一个有效的 PHP 回调。它可以是一个全局函数也可以是类中的一个方法。 如果是后者,它必须以一个数组的方式提供 : array($object,'methodName').

事件句柄的结构如下:

function methodName($event)
{
    ......
}

 

这里的 $event 即描述事件的参数(它来源于 raiseEvent() 调用)。 $event 参数是 CEvent 或其子类的实例。 至少,它包含了关于谁触发了此事件的信息。

从版本 1.0.10 开始,事件句柄也可以是一个 PHP 5.3 以后支持的匿名函数。例如,

$component->onClicked=function($event) {
    ......
}

 

如果我们现在调用 onClicked() onClicked 事件将被触发(在 onClicked() 中), 附属的事件句柄将被自动调用。

一个事件可以绑定多个句柄。当事件触发时, 这些句柄将被按照它们绑定到事件时的顺序依次执行。如果句柄决定组织后续句柄被执行,它可以设置 $event->handled true

 

=======================================================================

 

从这一句开始”我们可以附加一个方法到此 event “,读者可能 就不知道是什么意思了,于是看一下 CComponent 的源码:

 

/**
     * Raises an event.
     * This method represents the happening of an event. It invokes
     * all attached handlers for the event.
     * @param string the event name
     * @param CEvent the event parameter
     * @throws CException if the event is undefined or an event handler is invalid.
     */
    public function raiseEvent($name,$event)
{
	//事件名称同一小写化处理
        $name=strtolower($name);
		//先查看成员变量是否有以此命名的事件
        if(isset($this->_e[$name]))
        {
			//如果有,这个成员保存的是每一个事件处理器
			//以数组的方式保存
            foreach($this->_e[$name] as $handler)
            {
				//如果事件处理器是一个字符串,那么就是一个全局函数
                if(is_string($handler))
                    call_user_func($handler,$event);
				//如果不是,那么有可能是一个数组,该数组包含一个对象和方法名
				//参考http://php.net/manual/en/function.is-callable.php
                else if(is_callable($handler,true))
                {
                    // an array: 0 - object, 1 - method name
                    list($object,$method)=$handler;
					//如果对象是一个对象名
                    if(is_string($object))  // static method call
                        call_user_func($handler,$event);
					//判断对象是否有要调用的方法
                    else if(method_exists($object,$method))
                        $object->$method($event);
                	else
                        throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler       
"{handler}".',
                            array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));
                }
                else
                    throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler           
"{handler}".',
                        array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));
                // stop further handling if param.handled is set true
				//如果想停止继续循环获取事件的handler
//那么需要设置event的handled为true
                if(($event instanceof CEvent) && $event->handled)
                    return;
            }
        }
        else if(YII_DEBUG && !$this->hasEvent($name))
            throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
                array('{class}'=>get_class($this), '{event}'=>$name)));
		//如果_e中没有这个成员也没关系
    }

 

 

我们再看一下 CEvent 的代码( CComponent.php ):

class CEvent extends CComponent
{
    /**
     * @var object the sender of this event
     */
    public $sender;
    /**
     * @var boolean whether the event is handled. Defaults to false.
     * When a handler sets this true, the rest uninvoked handlers will not be invoked anymore.
     */
    public $handled=false;

    /**
     * Constructor.
     * @param mixed sender of the event
     */
    public function __construct($sender=null)
    {
        $this->sender=$sender;
    }
}

 

CEvent 只包含两个变量 $sender 记录事件触发者, $handled 表示事件是否已经被“解决”。

接着我们再看一下如何给一个组件注册一个事件处理器:

 

/**
     * Attaches an event handler to an event.
     *
     * An event handler must be a valid PHP callback, i.e., a string referring to
     * a global function name, or an array containing two elements with
     * the first element being an object and the second element a method name
     * of the object.
     *
     * An event handler must be defined with the following signature,
     * <pre>
     * function handlerName($event) {}
     * </pre>
     * where $event includes parameters associated with the event.
     *
     * This is a convenient method of attaching a handler to an event.
     * It is equivalent to the following code:
     * <pre>
     * $component->getEventHandlers($eventName)->add($eventHandler);
     * </pre>
     *
     * Using {@link getEventHandlers}, one can also specify the excution order
     * of multiple handlers attaching to the same event. For example:
     * <pre>
     * $component->getEventHandlers($eventName)->insertAt(0,$eventHandler);
     * </pre>
     * makes the handler to be invoked first.
     *
     * @param string the event name
     * @param callback the event handler
     * @throws CException if the event is not defined
     * @see detachEventHandler
     */
    public function attachEventHandler($name,$handler)
    {
        $this->getEventHandlers($name)->add($handler);
    }
    /**
     * Returns the list of attached event handlers for an event.
     * @param string the event name
     * @return CList list of attached event handlers for the event
     * @throws CException if the event is not defined
     */
    public function getEventHandlers($name)
    {
        if($this->hasEvent($name))
        {
            $name=strtolower($name);
            if(!isset($this->_e[$name]))
				//新建一个CList保存事件的处理器
                $this->_e[$name]=new CList;
            return $this->_e[$name];
        }
        else
            throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
                array('{class}'=>get_class($this), '{event}'=>$name)));
}

 

 

由此可以看出,首先获取事件处理器对象,如果没有则使用 CList Yii 实现的一个链表)创建,然后将事件处理器 add 进这个对象中,这样就可以在 raiseEvent 时遍历所有的事件处理器进行处理了,有点儿类似 jQuery 中注册了多个 click 事件处理器之后,当 click 事件触发时,会按顺序调用之前注册的事件处理器。

2
1
分享到:
评论
3 楼 silentime 2011-02-23  
呃,发现又一堆的格式代码,javaeye的富文本编辑器也不给力啊
2 楼 silentime 2011-02-23  
z.y.f 写道
男人,原来你在这里,你是在这里么?这里是你的主博客么?

目前算是吧,原来用新浪,但是新浪的代码引用太烂了,刚改不久
1 楼 z.y.f 2011-02-23  
男人,原来你在这里,你是在这里么?这里是你的主博客么?

相关推荐

    php yii源码分析

    在分析 Yii 源码时,我们首先要理解框架的基本结构和核心组件的工作原理。 1. **入口文件(index.php)**: 入口文件是每个 Web 应用程序的起点,对于 Yii 而言,`index.php` 文件是应用的入口。在这个文件中,Yii...

    Yii框架组件的事件机制原理与用法分析

    Yii框架的事件机制是其核心特性之一,它允许开发者在特定时刻插入自定义代码,以扩展或修改组件的行为。事件机制使得代码更加模块化和可扩展,而不必修改原始组件的内部实现。以下是对Yii框架组件事件机制的详细说明...

    yii-search:用于Yii2的elasticsearch

    2. 配置Yii2应用的组件,指定Elasticsearch服务器信息。 3. 在模型类中定义索引和映射,使用`yii\elasticsearch\ActiveRecord`作为基础类。 4. 创建和更新Elasticsearch索引,同步数据库数据。 5. 使用提供的查询...

    php yii2框架 普查平台

    Yii2提供了丰富的内置组件,如缓存、邮件发送、安全机制等,这些都可能在"普查平台"中得到应用。例如,为了提高性能,可能会使用缓存来存储常用数据;用户提交的敏感信息则需要通过加密和验证确保安全。 在表单处理...

    yii2-webadmin.rar

    2. **日志记录**:Yii2 内置了日志组件,可以记录应用程序运行时的各种事件,帮助开发者调试和追踪问题。日志可能会被分类到不同的级别,如 info、error 或 debug,方便分析。 3. **组件化开发**:Yii2 的组件化...

    yii2-statsd:Yii 2 的 statsd 组件,用于收集分析和其他指标

    3. **事件触发**:Yii 2的事件机制可以与statsd组件结合,使得在特定事件发生时自动发送统计信息,例如在每个HTTP请求结束后记录响应时间。 4. **自定义指标**:根据项目需求,开发者可以定义自己的指标来监控特定...

    Yii2中文手册(完整版)

    在性能优化方面,手册会介绍Yii2的缓存机制,包括数据缓存、页面缓存、片段缓存和HTTP缓存,以及如何使用Yii2的性能测试工具来分析和提升应用性能。安全章节则涵盖了用户认证、授权、防止SQL注入、XSS攻击等重要内容...

    Yii2 Starter Kit 2.3.2

    Yii2具有优秀的性能优化机制,如缓存、数据库查询优化等,同时还提供了丰富的内置组件,如安全、邮件、URL管理等,使得开发者可以快速构建复杂的Web应用程序。 AdminLTE则是一个流行的后台管理界面模板,它基于...

    yii-commentator:Yii评论模块

    - **配置应用**:在Yii框架的配置文件中,将评论模块注册为应用组件,设置必要的参数,如数据库连接、权限控制等。 - **视图集成**:在需要显示评论的视图文件中,调用模块提供的视图助手或模板,插入评论表单和展示...

    Yii框架执行流程及部分源码分析

    在Yii2中,请求组件被进一步优化为`yii\web\Request`。 5. **Run方法流程** 应用的`run()`方法是整个执行流程的核心。它会解析URL,调度到相应的控制器和动作,然后执行动作并返回响应。具体流程包括: - URL管理...

    yii源码

    Yii 2是基于组件的,这意味着很多功能都是由独立的、可重用的组件组成,开发者可以灵活地调整和替换这些组件来满足项目需求。 在"yii2-app-advanced-master"这个压缩包中,包含了一个高级模板应用,它是Yii 2的典型...

    Yii_PHP_框架分析

    本分析将深入探讨 Yii 的基本操作,包括框架的启动流程、类加载机制以及核心组件如 CWebApplication 的创建。 1. **框架启动流程** 框架的启动始于唯一的入口文件 `index.php`。在这个文件中,首先定义了 `YII_...

    yii-api:Yii REST API框架

    1. **Yii框架基础**:理解Yii的基础架构,如控制器、模型、视图、行为、事件、组件等,以及如何组织代码和配置文件。 2. **RESTful设计原则**:了解REST的基本概念,如资源、URI、HTTP方法、状态码、HATEOAS等,...

    yii-1.1.13源码

    2. **MVC设计模式**:Yii的核心是MVC模式,它使得业务逻辑、数据和用户界面分离。`yiisoft/yii/framework/controllers`包含控制器基类,`yiisoft/yii/framework/views`存储视图文件,`yiisoft/yii/framework/models`...

    Yii2最新手册中文完整版.zip

    - **组件系统**:Yii2的核心是组件系统,手册会阐述组件的概念,如何定义和使用组件,以及组件的事件和行为。 3. **数据库操作**: - **Active Record**:Yii2的Active Record允许直接在PHP对象上操作数据库记录...

    Yii2的基本应用程序模板 yii-basic-app-2.0.12

    - Yii2 的核心特性之一是组件化,每个对象都可以是一个组件,具有可配置性和可复用性。 4. **MVC模式**: - Model(模型):处理业务逻辑和数据操作。 - View(视图):负责展示数据,通常是HTML模板。 - ...

    YII框架开源项目

    2. **组件化设计**:Yii的所有功能都封装为可重用的组件,这使得开发过程更加模块化,便于扩展和定制。 3. **性能优化**:Yii内置了如数据库查询缓存、页面片段缓存、数据序列化等多种缓存策略,以提高应用性能。...

    Yii框架中使用PHPExcel的方法分析

    2. 使用`Yii::import()`方法导入PHPExcel库,强制包含防止加载时机过晚。 3. 理解Yii的自动加载机制,包括`YiiBase::autoload()`和`Yii::import()`的工作原理。 4. 调整PHPExcel的自动加载注册,确保其类能够被正确...

    YiiFramework

    - Debug Toolbar和Profiler组件用于调试和性能分析,帮助优化代码。 5. **Yii的扩展和社区**: - Yii拥有丰富的第三方扩展库,如用户认证、支付接口、图表库等,可以在Yii Extension Gallery找到。 - 社区活跃,...

Global site tag (gtag.js) - Google Analytics