Yii源码阅读笔记(八)
前面阅读了Yii2的两个基本类Object和Component,了解了Yii的三个重要概念属性、事件、行为,下面开始阅读Event类,Event类是所有事件类的基类:
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace yii\base; /** * Event is the base class for all event classes. * Event 是所有事件类的基类,是对Component的深化 * * It encapsulates the parameters associated with an event. * The [[sender]] property describes who raises the event. * And the [[handled]] property indicates if the event is handled. * If an event handler sets [[handled]] to be true, the rest of the * uninvoked handlers will no longer be called to handle the event. * * Additionally, when attaching an event handler, extra data may be passed * and be available via the [[data]] property when the event handler is invoked. * * @author Qiang Xue <qiang.xue@gmail.com> * @since 2.0 */ 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. * 事件的名字,通过[[Component::trigger()]] 和 [[trigger()]]方法设置,事件处理程序通过这个属性类检查处理的事件 */ 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. * * 触发事件的对象,如果未设置,则设置为调用"trigger()"方法的对象,如果是在静态环境下触发的类级别的事件,怎为空 */ 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; /** * @var array contains all globally registered event handlers. * 存储所有的 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: * * ```php * 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|object $class 定义的类级别的对象或者类名称. * @param string $name 事件名 * @param callable $handler 事件处理程序. * @param mixed $data 数据. * 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, '\\'); if ($append || empty(self::$_events[$name][$class])) { // 如果 append 为true,就放到 $_events 中名字为 $name 的数组的最后 self::$_events[$name][$class][] = [$handler, $data]; } else { //否则放到最前面 array_unshift(self::$_events[$name][$class], [$handler, $data]); } } /** * Detaches an event handler from a class-level event. * [[on()]]方法的反方法,移除一个类的事件 * This method is the opposite of [[on()]]. * * @param string|object $class 定义的类级别的对象或者类名称. * @param string $name 事件名 * @param callable $handler 事件处理程序. * 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 最左边的斜线 $class = ltrim($class, '\\'); if (empty(self::$_events[$name][$class])) { // 如果不存在该事件,返回false 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) { //如果删除成功,调用array_values方法重新赋值,初始化索引 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 定义的类级别的对象或者类名称. * @param string $name 事件名 * @return boolean whether there is any handler attached to the event. */ public static function hasHandlers($class, $name) { if (empty(self::$_events[$name])) { //如果不存在,直接返回false return false; } if (is_object($class)) { // 如果是一个 object,就获取其类名 get_class 内置函数,用于获取对象的方法 $class = get_class($class); } else { // 如果是一个类名,就去掉 class 最左边的斜杠 $class = ltrim($class, '\\'); } //将该类/该对象对应的类的父类以及该类/该对象对应的类实现的接口名称合并到一个数组中 $classes = array_merge( [$class], class_parents($class, true),//获取父类的类名 class_implements($class, true)//获取当前类和父类实现的所有接口类名 ); //判断是否存在事件处理程序,存在返回true foreach ($classes as $class) { if (!empty(self::$_events[$name][$class])) { return true; } } 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 定义的类级别的对象或者类名称. * @param string $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对象,为传入到handler函数中做准备 $event = new static; } $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, '\\');//去掉类名称左边的斜线 } //将该类/该对象对应的类的父类以及该类/该对象对应的类实现的接口名称合并到一个数组中 $classes = array_merge( [$class], class_parents($class, true), class_implements($class, true) ); foreach ($classes as $class) {//遍历所有的类 if (!empty(self::$_events[$name][$class])) {//找到符合条件的类 foreach (self::$_events[$name][$class] as $handler) { $event->data = $handler[1];//设置data数据 call_user_func($handler[0], $event);//调用处理程序 if ($event->handled) {//事件是否被处理标志为真,结束执行 return; } } } } } }
Yii源码阅读笔记(八)的更多相关文章
- Yii源码阅读笔记(一)
今天开始阅读yii2的源码,想深入了解一下yii框架的工作原理,同时学习一下优秀的编码规范和风格.在此记录一下阅读中的小心得. 每个框架都有一个入口文件,首先从入口文件开始,yii2的入口文件位于we ...
- Yii源码阅读笔记(二十八)
Yii/web中的Controller类,实现参数绑定,启动csrf验证功能,重定向页面功能: namespace yii\web; use Yii; use yii\base\InlineActio ...
- Yii源码阅读笔记(十八)
View中的查找视图文件方法和渲染文件方法 /** * Finds the view file based on the given view name. * 通过view文件名查找view文件 * ...
- Yii源码阅读笔记(三)
接着上次的继续阅读BaseYii.php vendor/yiisoft/yii2/BaseYii.php—— public static function getRootAlias($alias)// ...
- Yii源码阅读笔记(二)
接下来阅读BaseYii.php vendor/yiisoft/yii2/BaseYii.php—— namespace yii; use yii\base\InvalidConfigExceptio ...
- Yii源码阅读笔记(三十五)
Container,用于动态地创建.注入依赖单元,映射依赖关系等功能,减少了许多代码量,降低代码耦合程度,提高项目的可维护性. namespace yii\di; use ReflectionClas ...
- Yii源码阅读笔记(三十四)
Instance类, 表示依赖注入容器或服务定位器中对某一个对象的引用 namespace yii\di; use Yii; use yii\base\InvalidConfigException; ...
- Yii源码阅读笔记(三十三)
ServiceLocator,服务定位类,用于yii2中的依赖注入,通过以ID为索引的方式缓存服务或则组件的实例来定位服务或者组件: namespace yii\di; use Yii; use Cl ...
- Yii源码阅读笔记(三十二)
web/Application类的注释,继承base/Application类,针对web应用的一些处理: namespace yii\web; use Yii; use yii\base\Inval ...
随机推荐
- CodeIgniter报错: You must use the "set" method to update an entry
I'm using codeigniter/datamapper to develop an inviocing application and I'm getting an error that i ...
- Hierachy Viewer 使用 monitor命令
使用 Hierachy Viewer 可视化调试工具 Hierachy Viewer 能很方便地在开发者设计,调试和调整界面时,快速定位问题,解决问题,提高开发效率. Hierarchy Viewer ...
- 富士通F-02D 1630万像素翻盖手机docomo官方解锁送充电器
此款富士通F-02D手机是非常漂亮的一款拿在手上十分有质感的日版翻盖手机.2011年11月上市的新款手机.1630万像素的高清摄像头,防水,带指纹锁,高清HDMI输出,非常漂亮的手机灯光设计,其性能配 ...
- Java程序员最常用的8个Java日志框架
转自:http://www.codeceo.com/article/8-java-log-framework.html 作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用 ...
- 【Android】SlidingMenu属性详解(转)
原文:http://my.eoe.cn/1169143/archive/21892.html SlidingMenu简介:SlidingMenu的是一种比较新的设置界面或配置界面效果,在主界面左滑或者 ...
- dedecms创建或修改目录失败
并且后台修改系统参数无法写入! 原因是:文件夹无写入权限!
- AppleWatch开发教程之Watch应用对象新增内容介绍以及编写运行代码
AppleWatch开发教程之Watch应用对象新增内容介绍以及编写运行代码 添加Watch应用对象时新增内容介绍 Watch应用对象添加到创建的项目中后,会包含两个部分:Watch App 和 Wa ...
- parseFloat
parseFloat会把输入完整的数进行比较,不会比较中间数字.
- Logback常用配置详解
logback是一套日志框架,由log4j的优化版,由同一个作者开发,在速度和性能上都超过其他日志框架,再结合slf4j,已成为当前最流行的日志框架. Logback最常用就是在classpath定义 ...
- ASP.NET MVC 模型和数据对象映射实践
在使用 MVC 开发项目的过程中遇到了个问题,就是模型和数据实体之间的如何快捷的转换?是不是可以像 Entity Framework 的那样 EntityTypeConfiguration,或者只需要 ...