概念理解:在某一个事件(trigger)发生的时候,触发预先设定(on)的代码,这是代码解耦的一种方式。
事件按照级别分为三类
1. 实例级别
绑定事件、触发事件的类继承的是Component
,只在当前示例中运行,不与类的其他实例发生关系,也不与其他类、其他实例发生关系。
代码示例:
<?php
namespace common\components;
use yii\base\Component;
class EventTest extends Component
{
const EVENT_SAY_HELLO = 'say_hello';
public function sayHello($event)
{
echo $event->data;
$event->handled = true;
}
public function sayWorld($event)
{
echo $event->data;
}
}
1.绑定事件:
$event = new EventTest();
$event->on(EventTest::EVENT_SAY_HELLO, [$event, 'sayHello'], 'Hello!');
$event->on(EventTest::EVENT_SAY_HELLO, [$event, 'sayWorld'], 'World!');
2.解除事件:
$event->off(EventTest::EVENT_SAY_HELLO, [$event, 'sayHello']);
3.触发事件:
$event->trigger( EventTest::EVENT_SAY_HELLO);
2. 类级别
绑定事件、触发事件的类继承的是Event
,类级别事件会被类自身、类的实例、后代类、后代类实例的同一事件所触发,影响范围更大
代码示例:
<?php
namespace common\components;
use yii\base\Event;
class EventTest extends Event
{
const EVENT_SAY_HELLO = 'say_hello';
public function sayHello($event)
{
echo $event->data;
}
public function sayWorld($event)
{
echo $event->data;
}
}
1.绑定事件:
$event = new EventTest();
$event->on('\common\components\EventTest', EventTest::EVENT_SAY_HELLO, [$event, 'sayHello'], 'Hello!');
$event->on('\common\components\EventTest', EventTest::EVENT_SAY_HELLO, [$event, 'sayWorld'], 'World!');
2.解除事件:
$event->off('\common\components\EventTest', EventTest::EVENT_SAY_HELLO, [$event, 'sayWorld']);
3.触发事件:
$event->trigger('\common\components\EventTest', EventTest::EVENT_SAY_HELLO);
类级别参数比实例级别多一个参数:类名
注意:
解除事件如果不传 handle,则会解除该事件下的所有 handle。
在其中一个 handle 里面加上 $event->handled = true 也会阻止后续 handle 的触发,如上代码。
3. 全局级别
利用Application
实例在整个应用的生命周期中全局可访问的特性,来实现这个全局事件的。在任意需要的时候,都可以触发全局事件,也可以在任意必要的时候绑定,或解除一个事件。
代码示例:
1.绑定事件:
$event = new EventTest();
Yii::$app->on('global_event', [$event, 'globalEvent'], 'global event');
2.触发事件:
Yii::$app->trigger('global_event');
全局级别实际上也是一个特殊的实例。[注意所谓全局其实作用范围也只是在当前请求的生命周期有效,而非当前会话(简单的说,打开浏览器,访问服务器,直到浏览器关闭,称为一次会话)]
原理
实例级别通过维护Component
类的属性 $_events
数组,触发事件时通过[事件名称]取到[当前实例]的handle
数据,再通过函数call_user_func
触发handle
。
类级别通过维护Event
类的属性 $_events
数组,触发事件时通过[类名和事件名称]取到[当前类以及父类]的handle
数据,再通过函数call_user_func
触发handle
。
Component 的 $_event
数据结构示例如下
Array
(
[say_hello] => Array
(
[0] => Array
(
[0] => Array
(
[0] => common\components\EventTest Object
(
[_events:yii\base\Component:private] => Array
*RECURSION*
[_eventWildcards:yii\base\Component:private] => Array
(
)
[_behaviors:yii\base\Component:private] => Array
(
)
)
[1] => say_hello
)
[1] => Hello!
)
)
)
小结
以上总结参考了深入理解Yii2.0,其实以前就看过,但是也只是局限于看过,没有自己跑demo调试、查看源代码,然后就误以为自己明白了,其实过俩天什么都不记得了。所以现在通过写博客来加深自己的理解,这篇博客其实主要讲的还是事件的使用,具体原理一带而过,如果有小伙伴一知半解,可能查看一下源代码[yii\base\Component yii\base\Event
]你就明白了。由于水平有限,欢迎小伙伴交流和指正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。