Skip to content

添加事件

liaofei edited this page Jan 20, 2021 · 1 revision

先来看下官方文档是怎么样描述事件的。

新版的事件系统可以看成是5.1版本行为系统的升级版,事件系统相比行为系统强大的地方在于事件本身可以是一个类,并且可以更好的支持事件订阅者。
事件相比较中间件的优势是事件比中间件更加精准定位(或者说粒度更细),并且更适合一些业务场景的扩展。例如,我们通常会遇到用户注册或者登录后需要做一系列操作,通过事件系统可以做到不侵入原有代码完成登录的操作扩展,降低系统的耦合性的同时,也降低了BUG的可能性。

官方文档提供的操作方法有:

//直接使用事件类触发
Event::trigger('UserLogin');

//动态绑定
Event::bind(['UserLogin' => 'app\event\UserLogin']);

//手动注册监听
Event::listen('UserLogin', 'app\listener\UserLogin');

事件触发之前是需要注册事件监听的。

也就是说使用Event::trigger之前需要Event::listen注册事件的监听

我们只有了解了事件的真正意义,才能更好运用事件,下面我将从实际场景出发,教大家如何添加事件。 在正常工作中应该很容易遇到这样的问题:

今天做一个用户登录模块,用户的需求就是简单的用户登录,登录完成以后不需要其他操作。然后作为码农的你很开心的写起了代码,很快就完成了。

第二天,用户又提出了新的需求,用户登录以后需要把用户登录次数增加,并且记录下用户的登录IP。然后码农的你还是很开新的写起了代码,这个也简单,很快的完成了。

第三天,用户又又来了。用户登录以后如果不是常用IP地址给用户发个邮件提醒下账号存在风险。 第四天,用户登录以后如果不是常用IP地址给用户发个邮件并且发送短信提醒下账号存在风险。 …… 一个月以后,你的控制器,你的逻辑,不敢想象……

这个时候事件就是一个很好的解决方案。

下面是一个超级简单的事件用法。 首先是Model,定义了一个方法,获取用户ID为1的用户信息。大家一定要注意,我本来应该遵循框架seervices层调用dao层,dao层调用model层,最后将services层注入到事件类中,但是为了更直观更容易理解,我实例时直接将model实例注入,大家开发时请严格按照顺序。

namespace app\model;

use think\Model;

class User extends Model
{
    //获取用户ID为1的用户信息
    public function getUserInfo()
    {
        return self::where('id', 1)->find();
    }
}

然后用php think make:event User生成了一个User事件类,构造函数依赖注入UserModel;setLoginCount方法用于用户登录完成以后给用户登录次数+1(不要在意这个地方合不合理๑乛◡乛๑)。

namespace app\event;

use app\model\User as UserModel;

class User
{
    public $user;

    public function __construct(UserModel $user)
    {
        $this->user = $user;
    }

    //给用户登录次数+1
    public function setLoginCount()
    {
        $userInfo = $this->user->getUserInfo();
        $userInfo->login_count += 1;
        return $userInfo;
    }
}

定义了一个事件监听类User

namespace app\listener;

class User
{
    public function handle(\app\event\User $event)
    {
        $userInfo = $event->user->getUserInfo();
        echo 'listen监听器输出:' . json_encode($userInfo, JSON_UNESCAPED_UNICODE) . '<br />';
        echo 'listen监听器输出:' . json_encode($event->setLoginCount(), JSON_UNESCAPED_UNICODE) . '<br />';
    }
}

在控制器中执行

namespace app\controller;

use think\facade\Event;
use app\model\User;

class Index
{

    public function index()
    {
        //……在此之前一系列的登录操作
        $user = new User();
        $userInfo = $user->getUserInfo();
        echo '控制器输出:' . json_encode($userInfo, JSON_UNESCAPED_UNICODE) . '<br />';
        Event::listen('UserLogin', 'app\listener\User');
        Event::trigger('UserLogin');
    }

}

输出结果

控制器输出:{"id":1,"username":"路人甲","login_count":0}  
listen监听器输出:{"id":1,"username":"路人甲","login_count":0}  
listen监听器输出:{"id":1,"username":"路人甲","login_count":1}

可以看到用户登录+1已经被解耦了,相应的如果增加用户IP记录,给登录异常用户发送邮件都可以这样做。

Clone this wiki locally