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 ...
随机推荐
- Android_adb shell am/pm使用
转自:http://blog.sina.com.cn/s/blog_51335a0001017ux5.html adb shell am instrument [options] <COMP ...
- Java Hour 37 Weather ( 10 )
有句名言,叫做10000小时成为某一个领域的专家.姑且不辩论这句话是否正确,让我们到达10000小时的时候再回头来看吧. Hour 36 Weather 从失败的地方爬起来 在jsp 中,使用EL 表 ...
- php中base64_decode与base64_encode加密解密函数
php中base64_decode与base64_encode加密解密函数,实例分析了base64加密解密函数的具体用法,具有一定的实用价值,需要的朋友可以参考下 本文实例讲述了php中base64_ ...
- Android 贝塞尔曲线 折线图
1.贝塞尔曲线:http://baike.baidu.com/view/60154.htm,在这里理解什么是贝塞尔曲线 2.直接上图: 3.100多行代码就可以画出贝塞尔曲线,直接上代码 packag ...
- 简单几何(线段覆盖) POJ 3347 Kadj Squares
题目传送门 题意:告诉每个矩形的边长,它们是紧贴着的,问从上往下看,有几个还能看到. 分析:用网上猥琐的方法,将边长看成左端点到中心的距离,这样可以避免精度问题.然后先求出每个矩形的左右端点,然后如果 ...
- 记忆化搜索(DP+DFS) URAL 1183 Brackets Sequence
题目传送门 /* 记忆化搜索(DP+DFS):dp[i][j] 表示第i到第j个字符,最少要加多少个括号 dp[x][x] = 1 一定要加一个括号:dp[x][y] = 0, x > y; 当 ...
- HDU4081 Qin Shi Huang's National Road System(次小生成树)
枚举作为magic road的边,然后求出A/B. A/B得在大概O(1)的时间复杂度求出,关键是B,B是包含magic road的最小生成树. 这么求得: 先在原图求MST,边总和记为s,顺便求出M ...
- HangOver
HangOver Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- 【总结】String in Java
摘自:爪哇人的博客:http://hxraid.iteye.com/blog/522167/ J2SE - 语言基础与API JavaJVM虚拟机多线程数据结构 作者:每次上网冲杯Java时,都能看 ...
- HDU 4666 Hyperspace(曼哈顿距离)
题目链接 这是HDU第400个题. #include <cstdio> #include <cstring> #include <set> #include < ...