Thinkphp事件机制
firstime_tzjz 人气:0事件机制的实现有两种途径:通过监听、通过订阅
一、通过监听
1、创建监听类:在命令行模式下进入框架根目录执行
php think make:listener <自定义的类名>
例如:
php think make:listener UserListener
执行之后将在<框架根目录>\app\
listener\下生成
UserListener这个类。
2、配置监听:在<框架根目录>\app\event.php这个文件的listen数组中配置UserListener这个类,如下:
'listen' => [
'testEvent' => ['app\listener\UserListener']
],
3、触发监听:在你需要触发监听的地方加入如下代码
event('testEvent');
注意:这里的参数testEvent即为事件名称,可随便定义,但必须要与在event.php文件里配置的键名一致。
触发监听时你可以带上第二个参数。通过第二个参数你可以把任何数据传递到UserListener这个类中,也就是handle方法的参数(不明白啥意思的结合下面的完整代码理解)。
4、处理监听逻辑:在UserListener类的handle方法中完成业务逻辑
完整代码如下
Other:一个用来测试的类
<?php namespace app\controller; class Other { public function hello() { echo 'hello function'; } }
Index:触发监听的类
<?php namespace app\controller; use app\BaseController; class Index extends BaseController { public $name = 'index'; public function test1() { //触发监听事件,无参数 event('testEvent'); } public function test2() { //触发监听事件,传递字符串 event('testEvent', 'hello'); } public function test3() { //触发监听事件,传递自身类 event('testEvent', $this); } public function test4() { //触发监听事件,传递其他类 $other = new Other(); event('testEvent', $other); } }
UserListener:事件监听类
<?php namespace app\listener; class UserListener { /** * 事件监听处理 * * @return mixed */ public function handle($event) { //当调用Index类的test1方法时该代码有效,$event为null var_dump($event); //当调用Index类的test2方法时该代码有效,$event为字符串hello var_dump($event); //当调用Index类的test3方法时该代码有效,$event为Index类的实例 //可以访问Index类的name变量 echo $event->name; //当调用Index类的test4方法时该代码有效,$event为Other类的实例 //可以调用Other类的hello方法 echo $event->hello(); } }
二、通过订阅
1、创建订阅类
在命令行模式下进入框架根目录执行
php think make:subscribe <自定义的类名>
例如:
php think make:subscribe UserSubscribe
执行之后将在<框架根目录>\app\subscribe\下生成UserSubscribe这个类。
2、配置监听
在<框架根目录>\app\event.php这个文件的subscribe数组中配置UserSubscribe这个类,如下:
'subscribe' => ['app\subscribe\UserSubscribe'],
注意:为了测试效果,要把上面配置的UserListener从listen数组删除掉
3、触发监听
跟第一种途径一样
4、处理监听逻辑
处理监听的逻辑又有两种方法,我称之为自动绑定和手动绑定。手动绑定和自动绑定是互斥的,只能二选一。
4.1 自动绑定
在UserSubscribe类中添加ontestEvent方法,在该方法中完成业务逻辑。添加的方法名不能随意定义,规则是事件名称前面加上on。因为我们在event.php里定义的事件名称是testEvent,所以方法名就是ontestEvent(注意大小写)。监听方法定义之后就自动与事件绑定,所以我称之为自动绑定。
完整代码如下
Other和Index类的代码跟第一种途径一样
UserSubscribe:事件订阅类
<?php namespace app\subscribe; class UserSubscribe { public function ontestEvent($user) { //当调用Index类的test1方法时该代码有效,$event为null var_dump($user); //当调用Index类的test2方法时该代码有效,$event为字符串hello var_dump($user); //当调用Index类的test3方法时该代码有效,$event为Index类的实例 //可以访问Index类的name变量 echo $user->name; //当调用Index类的test4方法时该代码有效,$event为Other类的实例 //可以调用Other类的hello方法 echo $user->hello(); } }
4.2 手动绑定
首先,创建事件类,负责处理具体的业务逻辑。在命令行模式下进入框架根目录执行:
php think make:event <自定义的类名>
例如:
php think make:event UserEvent
执行之后将在<框架根目录>\app\event\下生成UserEvent这个类。
再在该类中定义一个handle方法,该方法有一个传入参数。方法名和传入的参数名可以任意定义。具体的业务逻辑就可以放在handle方法里面处理。
然后,在UserSubscribe类中添加subscribe方法,该方法传入参数为 Event 对象。然后在该方法中将监听的事件绑定到UserEvent类的handle方法上。如下:
$event->listen('testEvent', [app('app\event\UserEvent'), 'handle']);
完整代码如下
Other和Index类的代码跟第一种途径一样
UserSubscribe:事件订阅类
<?php declare (strict_types = 1); namespace app\subscribe; use think\Event; class UserSubscribe { public function subscribe(Event $event) { $event->listen('testEvent', [app('app\event\UserEvent'), 'handle']); } }
UserEvent:事件处理类
<?php declare (strict_types = 1); namespace app\event; class UserEvent { public function handle($user) { //当调用Index类的test1方法时该代码有效,$user为null var_dump($user); //当调用Index类的test2方法时该代码有效,$user为字符串hello var_dump($user); //当调用Index类的test3方法时该代码有效,$user为Index类的实例 //可以访问Index类的name变量 echo $user->name; //当调用Index类的test4方法时该代码有效,$user为Other类的实例 //可以调用Other类的hello方法 echo $user->hello(); } }
总结
1、通过监听的方式,每个事件都需要定义一个监听类来处理监听逻辑,并且在event.php的listen数组中配置
2、通过订阅的方式,如果采用自动绑定,则需要在订阅类中为每个事件定义一个监听方法(方法名不能自己定义),不需要定义subscribe方法;如果采用手动绑定,则定义subscribe方法,并为每一个事件绑定负责处理业务逻辑的具体方法(方法名可以自己定义)
3、通过监听的方式中,事件类基本上可有可无,因为创建的监听类本来就是专门处理对应的事件的业务逻辑的。并且监听类可以用事件类代替。
4、通过订阅的方式中,如果采用自动绑定,事件类也没有必要,因为在订阅类中为每个事件定义的监听方法本来就是专门处理对应的事件的业务逻辑的。如果采用手动绑定,也可以把监听方法写在订阅类中,那么事件类也就没必要了。但是个人认为手动绑定还是使用事件类比较好。订阅类只负责绑定,事件类负责处理具体业务逻辑,这样结构上比较清晰
5、其实通过监听的方式中,监听类(例子中的UserListener)可以替换成其他命名空间下的其他类,只要该类有一个handle方法就行,比如事件类。替换之后记得要在event.php配置文件中做对应修改。同理,通过订阅的方式中,也可以将订阅类(例子中的UserSubscribe)直接替换为其他类,但是要记得自动绑定需要在该类下有符合命名规则的方法,手动绑定需要在该类下有一个subscribe方法
加载全部内容