先吐槽下:TP简直就是个半成品,参考手册真的是只能用于参考,搞不清楚的时候还是直接看源码吧。
事件的本质就是用于代码解耦,简单的理解可以认为是在代码里加的钩子函数。使用起来可以分成两种情况,使用事件类和不使用事件类,推荐使用事件类。
使用步骤
使用事件类的步骤:
- 定义事件类,在event.php中添加事件类的绑定。(事件类可以认为是用于传递变量的介质)
- 定义事件监听类,在event.php中添加事件监听。(绑定和监听的键名建议相同,推荐使用事件的类名[不带命名空间])
- 在需要触发事件的位置,使用trigger()方法触发事件。
不使用事件类的步骤:
官方手册说可以不定义事件类,仅使用监听就行。这个说法经测试是可行的,因为监听处理方法的第一个参数(仅有一个参数)不指定类型的情况,可以传任意对象(变量)。
- 定义监听类,在event.php中添加事件监听。(没有绑定事件,所以键名就没要求了)
- 在需要触发事件的位置,使用trigger('键名'[, 参数(仅支持一个,要传多个参数就给个数组)])方法触发事件。
示例代码
使用事件类的方式
1. 使用命令新建事件类文件:(手动建也没问题)
php think make:event TestEvent
会生成文件:app\event\TestEvent.php
2. 打开文件并修改:
<?php
declare(strict_types=1);
namespace app\event;
class TestEvent
{
private $id = 0;
public function __construct($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
}
3. 添加事件绑定,修改文件:app\event.php。(建议事件都写在文件里,不要用动态绑定)
<?php
// 事件定义文件
return [
'bind' => [
'TestEvent' => 'app\event\TestEvent'
],
.................
];
4. 使用命令新建监听处理类,类文件:app\listener\TestEventListener.php
<?php
declare(strict_types=1);
namespace app\listener;
use app\event\TestEvent;
class TestEventListener
{
/**
* 事件监听处理
*
* @param TestEvent $event 这里指定参数为定义好的事件类,触发时必须使用这个类的实例触发
* @return mixed
*/
public function handle(TestEvent $event)
{
echo 'TestEvent 事件监听处理 TestEvent Id: ' . $event->getId();
}
}
5. 注册监听,修改文件:app\event.php
<?php
// 事件定义文件
return [
'bind' => [
'TestEvent' => 'app\event\TestEvent',
],
'listen' => [
'TestEvent' => ['app\listener\TestEventListener'],
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
...........................
];
6. 控制器或其它地方触发事件:
<?php
declare(strict_types=1);
namespace app\test\controller;
use app\BaseController;
use app\event\TestEvent;
use think\facade\Event;
class EventTest extends BaseController
{
/**
* 事件测试
*
* @return void
*/
public function eventTest()
{
/**
* 使用事件类实例触发
* 这种情况要求:绑定和监听的键名必须相同,而且键名必须是事件的类名(不带命名空间)
*/
Event::trigger(new TestEvent(12));
/**
* 使用绑定事件的键名触发绑定的事件,监听的键名与绑定事件的键名不同时可用于触发指定的监听
*
* 如:app\evnet.php中的设置为:
*
* <?php
* // 事件定义文件
* return [
*
* 'bind' => [
* 'TestEvent' => 'app\event\TestEvent',
* ],
*
* 'listen' => [
* 'TestEvent1' => ['app\listener\TestEventListener'],
* ..................
* ],
* ...................
* ];
*/
Event::trigger('TestEvent1', new TestEvent(13)); // 调用不存在的监听键,没代码被执行
}
}
不使用事件类的方式
1. 定义监听类
<?php
declare (strict_types = 1);
namespace app\listener;
class UserLoginListener
{
/**
* 事件监听处理
*
* @return mixed
*/
public function handle($event)
{
//
echo 'UserLoginListener. <br>';
print_r($event); // 参数为触发时传过来的变量(任意类型)
echo '<br>';
}
}
2. 注册监听
'listen' => [
'UserLoginEvent' => ['app\listener\UserLoginListener'],
...................
],
3. 触发事件
public function eventListenerTest()
{
Event::trigger('UserLoginEvent'[, 参数]); // 参数可以任意类型
}
结尾:还有一种方式是事件订阅的方式,感觉这种方式对于解耦并不友好,所以就不写了。如果有需要可以看下(参考)参考手册。