0

0

Yii2的深入学习-yiibaseEvent 类

php中文网

php中文网

发布时间:2016-06-13 12:28:13

|

1067人浏览过

|

来源于php中文网

原创

Yii2的深入学习--yii\base\Event 类

根据之前一篇文章,我们知道 yii2 的事件分两类,一是类级别的事件,二是实例级别的事件。类级别的事件是基于 yii\base\event 实现,实例级别的事件是基于 yii\base\component 实现。

今天先来看下类级别事件的实现,代码是 yii\base\Event 类。

phpnamespace yii\base;/** * Event is the base class for all event classes. */class Event extends Object{    /**     * @var string the event name. This property is set by [[Component::trigger()]] and [[trigger()]].     * Event handlers may use this property to check what event it is handling.     * 事件的名字     */    public $name;    /**     * @var object the sender of this event. If not set, this property will be     * set as the object whose "trigger()" method is called.     * This property may also be a `null` when this event is a     * class-level event which is triggered in a static context.     * 触发事件的对象     */    public $sender;    /**     * @var boolean whether the event is handled. Defaults to false.     * When a handler sets this to be true, the event processing will stop and     * ignore the rest of the uninvoked event handlers.     * 记录事件是否已被处理,当 handled 被设置为 true 时,执行到这个 event 的时候,会停止,并忽略剩下的 event     */    public $handled = false;    /**     * @var mixed the data that is passed to [[Component::on()]] when attaching an event handler.     * Note that this varies according to which event handler is currently executing.     */    public $data;    /**     * 存储所有的 event,因为是 static 的属性,所有的 event 对象/类都共享这一份数据     */    private static $_events = [];    /**     * Attaches an event handler to a class-level event.     *     * When a class-level event is triggered, event handlers attached     * to that class and all parent classes will be invoked.     *     * For example, the following code attaches an event handler to `ActiveRecord`'s     * `afterInsert` event:     *     * ~~~     * Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {     *     Yii::trace(get_class($event->sender) . ' is inserted.');     * });     * ~~~     *     * The handler will be invoked for EVERY successful ActiveRecord insertion.     *     * For more details about how to declare an event handler, please refer to [[Component::on()]].     *     * 为一个类添加事件     *     * @param string $class the fully qualified class name to which the event handler needs to attach.     * @param string $name the event name.     * @param callable $handler the event handler.     * @param mixed $data the data to be passed to the event handler when the event is triggered.     * When the event handler is invoked, this data can be accessed via [[Event::data]].     * @param boolean $append whether to append new event handler to the end of the existing     * handler list. If false, the new handler will be inserted at the beginning of the existing     * handler list.     * @see off()     */    public static function on($class, $name, $handler, $data = null, $append = true)    {        // 去掉 class 最左边的斜杠        $class = ltrim($class, '\\');        // 如果 append 为true,就放到 $_events 中名字为 $name 的数组的最后,否则放到最前面        if ($append || empty(self::$_events[$name][$class])) {            self::$_events[$name][$class][] = [$handler, $data];        } else {            array_unshift(self::$_events[$name][$class], [$handler, $data]);        }    }    /**     * Detaches an event handler from a class-level event.     *     * This method is the opposite of [[on()]].     *     * 移除一个类的事件     *     * @param string $class the fully qualified class name from which the event handler needs to be detached.     * @param string $name the event name.     * @param callable $handler the event handler to be removed.     * If it is null, all handlers attached to the named event will be removed.     * @return boolean whether a handler is found and detached.     * @see on()     */    public static function off($class, $name, $handler = null)    {        $class = ltrim($class, '\\');        if (empty(self::$_events[$name][$class])) {            // 不存在该事件            return false;        }        if ($handler === null) {            // 如果 handler 为空,直接将在该类下该事件移除,即移出所有的是这个名字的事件            unset(self::$_events[$name][$class]);            return true;        } else {            $removed = false;            // 如果 $handler 不为空,循环 $_events 找到相应的 handler,只移除这个 handler 和 data 组成的数组            foreach (self::$_events[$name][$class] as $i => $event) {                if ($event[0] === $handler) {                    unset(self::$_events[$name][$class][$i]);                    $removed = true;                }            }            if ($removed) {                // 移除之后,使数组重新变成一个自然数组                self::$_events[$name][$class] = array_values(self::$_events[$name][$class]);            }            return $removed;        }    }    /**     * Returns a value indicating whether there is any handler attached to the specified class-level event.     * Note that this method will also check all parent classes to see if there is any handler attached     * to the named event.     * 检测在某个类或者对象是否具有某个事件     * @param string|object $class the object or the fully qualified class name specifying the class-level event.     * @param string $name the event name.     * @return boolean whether there is any handler attached to the event.     */    public static function hasHandlers($class, $name)    {        if (empty(self::$_events[$name])) {            // 不存在,直接返回            return false;        }        if (is_object($class)) {            // 如果是一个 object,就获取其类名            $class = get_class($class);        } else {            // 如果是一个类名,就去掉 class 最左边的斜杠            $class = ltrim($class, '\\');        }        // 如果该类中找不到,就去父类中找,直到找到或者没有父类了为止        do {            if (!empty(self::$_events[$name][$class])) {                return true;            }        } while (($class = get_parent_class($class)) !== false);        return false;    }    /**     * Triggers a class-level event.     * This method will cause invocation of event handlers that are attached to the named event     * for the specified class and all its parent classes.     * 触发某个类或者对象的某个事件     * @param string|object $class the object or the fully qualified class name specifying the class-level event.     * @param string $name the event name.     * @param Event $event the event parameter. If not set, a default [[Event]] object will be created.     */    public static function trigger($class, $name, $event = null)    {        if (empty(self::$_events[$name])) {            return;        }        if ($event === null) {            // 事件不存在,就创建一个 Event 对象            $event = new static;        }        // 设置event对象的属性,默认是未被处理的        $event->handled = false;        $event->name = $name;        if (is_object($class)) {            if ($event->sender === null) {                // 如果 $class 是个对象,并且是 sender 为空,就将 $class 赋给 sender,即 $class 就是触发事件的对象                $event->sender = $class;            }            $class = get_class($class);        } else {            $class = ltrim($class, '\\');        }        // 循环类的 $_event,直到遇到 $event->handled 为真或者没有父类了为止        do {            if (!empty(self::$_events[$name][$class])) {                foreach (self::$_events[$name][$class] as $handler) {                    // 将参数赋到 event 对象的 data 属性上                    $event->data = $handler[1];                    // 调用 $handler 方法                    // 在方法中,可以用 $this->data 取到相应的参数                    // 也可以在其中设置 $this->handled 的值,中断后续事件的触发                    call_user_func($handler[0], $event);                    // 当某个 handled 被设置为 true 时,执行到这个事件的时候,会停止,并忽略剩下的事件                    if ($event->handled) {                        return;                    }                }            }        } while (($class = get_parent_class($class)) !== false);    }}

通过上面代码可以看出,类级别的 Event,其本质就是在 Event 类中的 $_events 变量中存储事件,触发事件的时候,只需将其取出,执行即可。

$_events里面的数据结构大概如下:

[    'add' => [        'Child' => [            [function ($event) { ... }, $data],            [[$object, 'handleAdd'], null],            [['ChildClass', 'handleAdd'], $data],            ['handleAdd', $data]        ],        'ChildClass' => [            ...        ]    ],    'delete' => [        ...    ]]

之后讲到yii\base\Component类时,我们会再来说一下实例级别的事件。

 

宠物商店
宠物商店

目前,PetShop已经从最初的2.0、3.0等版本,发展到了最新的4.0版本。PetShop 4.0使用ASP.NET 2.0技术开发,其中加入了众多新增特性,因此,在性能、代码数量、可扩展性等方面有了重大改善。可以说,学习PetShop 4.0是深入掌握ASP.NET 2.0技术的捷径。本节将引领读者逐步了解PetShop 4.0的方方面面,包括应用程序安装、功能和用户界面简介、解决方案和体系

下载

 

对 Yii2 源码有兴趣的同学可以关注项目 yii2-2.0.3-annotated,现在在上面已经添加了不少关于 Yii2 源码的注释,之后还会继续添加~

 

有兴趣的同学也可以参与进来,提交 Yii2 源码的注释。

 

 

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

2

2026.02.06

java多线程方法汇总
java多线程方法汇总

本专题整合了java多线程面试题、实现函数、执行并发相关内容,阅读专题下面的文章了解更多详细内容。

0

2026.02.06

1688阿里巴巴货源平台入口与批发采购指南
1688阿里巴巴货源平台入口与批发采购指南

本专题整理了1688阿里巴巴批发进货平台的最新入口地址与在线采购指南,帮助用户快速找到官方网站入口,了解如何进行批发采购、货源选择以及厂家直销等功能,提升采购效率与平台使用体验。

90

2026.02.06

快手网页版入口与电脑端使用指南 快手官方短视频观看入口
快手网页版入口与电脑端使用指南 快手官方短视频观看入口

本专题汇总了快手网页版的最新入口地址和电脑版使用方法,详细提供快手官网直接访问链接、网页端操作教程,以及如何无需下载安装直接观看短视频的方式,帮助用户轻松浏览和观看快手短视频内容。

15

2026.02.06

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

10

2026.02.06

Python 微服务架构与 FastAPI 框架
Python 微服务架构与 FastAPI 框架

本专题系统讲解 Python 微服务架构设计与 FastAPI 框架应用,涵盖 FastAPI 的快速开发、路由与依赖注入、数据模型验证、API 文档自动生成、OAuth2 与 JWT 身份验证、异步支持、部署与扩展等。通过实际案例,帮助学习者掌握 使用 FastAPI 构建高效、可扩展的微服务应用,提高服务响应速度与系统可维护性。

6

2026.02.06

JavaScript 异步编程与事件驱动架构
JavaScript 异步编程与事件驱动架构

本专题深入讲解 JavaScript 异步编程与事件驱动架构,涵盖 Promise、async/await、事件循环机制、回调函数、任务队列与微任务队列、以及如何设计高效的异步应用架构。通过多个实际示例,帮助开发者掌握 如何处理复杂异步操作,并利用事件驱动设计模式构建高效、响应式应用。

7

2026.02.06

java连接字符串方法汇总
java连接字符串方法汇总

本专题整合了java连接字符串教程合集,阅读专题下面的文章了解更多详细操作。

25

2026.02.05

java中fail含义
java中fail含义

本专题整合了java中fail的含义、作用相关内容,阅读专题下面的文章了解更多详细内容。

28

2026.02.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
前端系列快速入门课程
前端系列快速入门课程

共4课时 | 0.4万人学习

react hooks实战移动端企业级项目
react hooks实战移动端企业级项目

共59课时 | 6.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号