关于Thinkphp6中事件以及其定义、绑定、监听与订阅

方滴云WEB2022-04-24 08:40

关于Thinkphp6中事件,之前的理解一直不太明了,主要还是因为它有些抽象,所以理解起来,有些费劲了。

首先我们看下官方文档,https://www.kancloud.cn/manual/thinkphp6_0/1037492。官方提及事件可以作为一个类,为我们提供更加精准、精细的服务。

关于事件的使用,我们可以这么理解它。首先,我们需要定义事件,定义好事件后,我们可监听事件或订阅事件,监听或订阅的事件可以在控制器中进行触发。当然,我觉得他在消息列队或定时任务中都应该可以触发(没试过)。

1. 事件定义

这个地方,老实说有一些不好理解。在定义事件的时候,我们可以定义一个事件类,也可以不定义事件类。这也是很多盆友觉得event.php中bind数组没得啥用的原因。

我们用个粗暴点的方式来理解它吧。一切操作皆为事件,我们可以通过定义一个事件类的方式来定义一个事件,当然也可以使用应用中本身的操作。

不同之处在于,定义的事件类要进行绑定。绑定方式有两种,第一种是在event.php中的bind数组中进行批量绑定,也可以使用Event::bind();的方式进行动态绑定,具体可以参考官方文档。

官方也说明了,如果没有定义事件类的话,则无需绑定。对于大部分的场景,可能确实不需要定义事件类。就我个人理解而言,事件绑定也就是给定义的事件一个别名吧。

2. 事件监听

这里开始才是正席。我们的目的是干活儿,比如我们要监听某个事件,简单的说,就是当某件事儿做了后,我们同事还要做点啥。

网友们给出了一个调侃的应用场景——客户让开发个会员登录注册模块。开始需求很简单,注册登录下就完了。

于是,我们开始愉快的写代码了。很快,工作完成了。

但是,客户的需求没有完。能不能注册完了给用户发个邮件,祝贺下人家注册成功了。是的,很简单,你愉快的敲起来了,很快你的工作又完成了。

不出意外,还有很多需求等着你。比如,注册成功也能不能同时发个短信?登录了能不能收集下用户的Ip等信息?发现用户不在常用地IP登录,能不能发个安全提示邮件?用户三个月没有改密码了,能不能登录的时候发个邮件提示下定期改密码......

当然了,都能!但是你们当初那个登录注册页面可能已经惨不忍堵了。或者说其中某些功能,曾经做过,能不能减少代码耦合快速接上呢?

是的,这里的事件,就是来解决这个问题的。曾经我们叫它钩子、行为。相较于事件而言,事件低耦合,同时还是异步完成的,效率与体验更好。

好了,废话说完了。我们先来监听事件。这里的事件监听其实也有两种方式。

第一种,在event.php中的listen数组中进行批量监听;第二种通过Event::listen()的方式进行动态监听。下面我们通过代码来走下流程。

首先我们定义一个事件监听类,当然官方文档中也提到,可以通过Event::listen('UserLogin', function($user) { })的方式定义一个监听,其实有三种了,这里我们定义事件类,如下图所示。

事件监听类只需要定义一个handle方法,支持依赖注入。这里我们在handle方法中传入了一个参数。同时在event.php的listen数组中添加监听:'DemoListen' => [\app\listener\DemoListen::class],然后我们在控制器中调用。

运行后,我们可以在控制台查看消息列队的结果,在调试工具中查看事件监听的结果,如下图所示。

为了更好的说明问题,我们同时还定义两个监听类,FdyAction1与FdyAction2,内容很简单,就是打印下结果。然后我们只绑定FdyAction1,看下使用情况。

控制器中,我们这样写

FdyAction1直接触发,但是FdyAction2,我这里做动态监听,看下运行结果,是不是我们预想的。

是的,没有让我们失望,它跑起来了。下面我们看看手动注册监听事件的使用。

为了效果,我还在DemoSubscribe中对FdyTestEvent进行了定义,下面我们看下执行结果吧。

至于这里的事件监听,是在配置中批量监听还是在控制器(不限于)动态监听,又或是手动注册监听,官方也没给出推荐,所以使用就看心情吧。下面我们来看事件订阅。

3. 事件订阅

有了事件监听,为什么还要订阅?这个问题,我也问过自己很多遍,下面我们通过测试来说明下它解决的问题。

如上图,我们定义一个订阅类,同时在event.php的suscribe数组中添加订阅事件类,如下图。

控制器中,我们做下简单的调整,如下图所示

我再看得到的结果

从这里看不出明显的效果对吧,我个人的理解就是可以把批量监听都写到订阅中,进一步精减代码。

比如在event.php的listen数组中有很多类似的方法需要监听,按常规的写法,我们需要批量监听,或者在使用的时候动态监听,而使用了订阅后,就简单了,直接全部写在一起,使用上更加简洁了。

监听事件的方法命名规范是on+事件标识(驼峰命名)。如果希望自定义订阅方式(或者方法规范),可以定义subscribe方法实现。这里需要注意的是,它use的是think/Event类。

到此,就基本说完了。关于事件类,这里我没有涉及,主要是目前也没有发现他的应用场景吧。后续涉及到,再行补充吧。

总结

从解决问题的解决来看,个人觉得这个东西其实主要就是把同步的操作变成了异步,同时降低代码间的耦合,从而提升代码的易维护性。