ThinkPHP6 关于事件的简单应用

发布时间 2023-12-20 16:13:53作者: 疯子丶pony

一、序章

ThinkPHP6的手册中关于【事件】章节的介绍都是直接文字说明,给出创建的类文件,并没有一个好的示例来进行补充说明。对于刚接触【事件】的同学在阅读理解上增加了一点点困难,本文就在此结合示例简单叙述下。

 

二、事件

事件的使用分两种方式,一个是不使用事件类,另一个使用事件类。

1、不使用事件类

(1)使用 php think 创建一个监听类

php think make:listener UserListener

(2)打开 UserListener 类文件,echo 出 【UserListener 监听处理】,成功输入表示进入到了监听内部。

<?php
declare (strict_types = 1);

namespace app\listener;

class UserListener
{
    /**
     * 事件监听处理
     *
     * @return mixed
     */
    public function handle($event)
    {
        // 事件监听处理
        echo $event.': UserListener 监听处理<br>';
    }
}

(3)注册监听。找到并打开【路径:根目录/app/event.php】event.php文件,添加内容如下:

<?php
// 事件定义文件
return [
    'bind'      => [
    ],

    'listen'    => [
        'AppInit'  => [],
        'HttpRun'  => [],
        'HttpEnd'  => [],
        'LogLevel' => [],
        'LogWrite' => [],
        //注册监听类
        'User' => ['app\listener\UserListener'],
    ],

    'subscribe' => [
    ],
];

(4)触发事件。在需要触发的业务代码中调用。

<?php
/**
 * Created by PhpStorm
 * Author: fengzi
 * Date: 2023/12/15
 * Time: 17:24
 */

namespace app\admin\controller;

use think\facade\Event;

class LoginController extends AdminBaseController
{
    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
    }

    public function login()
    {
        echo "登录成功<br>";
        
        // 触发User事件
        Event::trigger('User', '第一次');

        // 使用助手函数触发User事件
        event('User', '第二次');
    }
}

 

(5)使用效果展示。图中分别展示了在第(4)步中的三次输出,说明调用成功。User事件调用了两次,所以输出了两次。

 

(6)上面的示例为自动注册监听。还有一种是自己手动注册监听。前面(1)和(2)的步骤都是一样的,这里就不在重复贴代码了,到第(3)步时不需要注册。

<?php
// 事件定义文件
return [
    'bind'      => [
    ],

    'listen'    => [
        'AppInit'  => [],
        'HttpRun'  => [],
        'HttpEnd'  => [],
        'LogLevel' => [],
        'LogWrite' => [],
    ],

    'subscribe' => [
    ],
];

(7)触发事件。在需要触发的业务代码中手动注册并调用。

<?php
/**
 * Created by PhpStorm
 * Author: fengzi
 * Date: 2023/12/15
 * Time: 17:24
 */

namespace app\admin\controller;

use think\facade\Event;

class LoginController extends AdminBaseController
{
    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
    }

    public function login()
    {
        echo "登录成功<br>";

        // 注册User事件
        Event::listen('User', 'app\listener\UserListener');

        echo '注册成功,触发User事件<br>';

        // 触发User事件
        Event::trigger('User', '第一次');

        // 使用助手函数触发User事件
        event('User', '第二次');
    }
}

(8)使用效果展示。

 

(9)总结

不管是自动注册还是手动注册,都要注意绑定的事件名称要相同,不然无法监听成功。

 

2、使用事件类

(1)创建事件类文件

php think make:event UserEvent

(2)在【根目录/app/event】在找到UserEvent文件,修改成如下内容:

<?php
declare (strict_types = 1);

namespace app\event;

class UserEvent
{
    private $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }
}

(3)在【根目录/app/event.php】文件中添加UserEvent的事件绑定

<?php
// 事件定义文件
return [
    'bind'      => [
        'userEvent' => 'app\event\UserEvent',
    ],

    'listen'    => [
        'AppInit'  => [],
        'HttpRun'  => [],
        'HttpEnd'  => [],
        'LogLevel' => [],
        'LogWrite' => [],
    ],

    'subscribe' => [
    ],
];

(4)创建事件监听类

php think make:listener UserListener

(5)在【根目录/app/event.php】文件中注册UserListener的监听类

<?php
// 事件定义文件
return [
    'bind'      => [
        'userEvent' => 'app\event\UserEvent',
    ],

    'listen'    => [
        'AppInit'  => [],
        'HttpRun'  => [],
        'HttpEnd'  => [],
        'LogLevel' => [],
        'LogWrite' => [],
        //注册监听类
        'UserEvent' => ['app\listener\UserListener'],
    ],

    'subscribe' => [
    ],
];

(6)打开 UserListener.php 文件,修改内容如下:

<?php
declare (strict_types = 1);

namespace app\listener;

class UserListener
{
    /**
     * 事件监听处理
     *
     * @return mixed
     */
    public function handle($event)
    {
        echo $event->getName().'<br>';
    }
}

(7)触发事件。在需要触发的业务代码中调用。

<?php
/**
 * Created by PhpStorm
 * Author: fengzi
 * Date: 2023/12/15
 * Time: 17:24
 */

namespace app\admin\controller;

use app\event\UserEvent;
use think\facade\Event;

class LoginController extends AdminBaseController
{
    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
    }

    public function login()
    {
        echo "登录成功<br>";

        /**
         * 第一种触发User事件写法
         * 参数1:监听名称
         *   必须保证和event.php文件中的【listen】数组中的键名一致,否则无法调用成功。
         *   本示例中event.php文件里配置的键值是【UserEvent】
         * 参数2:事件
         *   事件对象
         */
        Event::trigger('UserEvent', new UserEvent('张三'));

        /**
         * 第二种触发User事件写法
         * 这种写法必须保证和event.php文件中的【bind】和【listen】的键名一致,否则无法调用成功。
         */
        Event::trigger(new UserEvent('李四'));
    }
}

(8)运行结果展示。

(9)总结

个人理解:事件类好比发邮件这个动作,发邮件的一系列动作都写在了事件类中(其实可以看做一个独立的邮件类文件)。在你需要发送邮件的时候通过【Event::trigger()】触发一下,就可以发送邮件了。

 

三、事件订阅

1、事件订阅

这种方式相当于把事件写在了订阅类中,订阅类中的一个方法就是一个事件。

(1)使用 php think 创建一个订阅类

php think make:subscribe UserSubscribe

(2)打开 UserSubscribe 类文件,修改内容如下:

<?php
declare (strict_types = 1);

namespace app\subscribe;

class UserSubscribe
{
    public function onName($event)
    {
        echo $event.'<br>';
    }
}

(3)注册订阅。找到并打开【地址:根目录/app/event.php】event.php文件,添加内容如下:

<?php
// 事件定义文件
return [
    'bind'      => [
    ],

    'listen'    => [
        'AppInit'  => [],
        'HttpRun'  => [],
        'HttpEnd'  => [],
        'LogLevel' => [],
        'LogWrite' => [],
    ],

    'subscribe' => [
        'app\subscribe\UserSubscribe',
    ],
];

(4)触发事件。在需要触发的业务代码中调用。

<?php
/**
 * Created by PhpStorm
 * Author: fengzi
 * Date: 2023/12/15
 * Time: 17:24
 */

namespace app\admin\controller;

use think\facade\Event;

class LoginController extends AdminBaseController
{
    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
    }

    public function login()
    {
        echo "登录成功<br>";

        /**
         * 手动注册订阅
         * 如果手动注册订阅类,则不需要在配置文件(event.php)中注册,这步按需使用。
         */
        Event::subscribe('app\subscribe\UserSubscribe');

        /**
         * 触发事件
         * 参数1:事件名称,必须与[app\subscribe\UserSubscribe.php]文件中定义的方法名称相同(方法名要除去固定格式on)
         *   例如:事件方法名称为:onName,则参数1的标识名称就为:Name
         * 参数2:传递给事件处理函数的数据
         */
        Event::trigger('Name', '张三,33岁');

        /**
         * 触发事件(使用助手函数)
         * 参数1:事件名称,必须与[app\subscribe\UserSubscribe.php]文件中定义的方法名称相同(方法名要除去固定格式on)
         *   例如:事件方法名称为:onName,则参数1的标识名称就为:Name
         * 参数2:传递给事件处理函数的数据
         */
        event('Name', '李四,34岁');
    }
}

(5)结果展示

 

2、自定义订阅

这种方式相当于在自定义订阅中调用事先定义好的事件类(项目根目录/app/event下的文件),然后自行绑定调用关系。

(1)使用 php think 创建一个事件类

php think make:event UserEvent

(2)打开 UserEvent 类文件,修改内容如下:

<?php
declare (strict_types = 1);

namespace app\event;

class UserEvent
{
    /**
     * @param $params
     * @return mixed
     */
    public function getName($params)
    {
        // 打印name字段的数据
        echo $params['name'];

        // 返回传入的数据
        return $params;
    }

    /**
     * @param $params
     * @return mixed
     */
    public function getAge($params)
    {
        // 打印age字段的数据
        echo $params['age'];

        // 返回传入的数据
        return $params;
    }
}

(3)使用 php think 创建一个订阅类

php think make:subscribe UserSubscribe

(4)打开 UserSubscribe 类文件,修改内容如下:

<?php
declare (strict_types = 1);

namespace app\subscribe;

use app\event\UserEvent;
use think\Event;

class UserSubscribe
{
    /**
     * 自定义订阅
     * @param Event $event
     * @return void
     * @Author: fengzi
     */
    public function subscribe(Event $event)
    {
        // UserEvent::class 为第(2)步中创建的事件类,getName为事件类中的方法名称
        $event->listen('name', [UserEvent::class, 'getName']);

        // UserEvent::class 为第(2)步中创建的事件类,getAge为事件类中的方法名称
        $event->listen('age', [UserEvent::class, 'getAge']);
    }
}

(5)注册订阅类。配置注册文件event.php,内容如下:

<?php
// 事件定义文件
return [
    'bind'      => [
    ],

    'listen'    => [
        'AppInit'  => [],
        'HttpRun'  => [],
        'HttpEnd'  => [],
        'LogLevel' => [],
        'LogWrite' => [],
    ],

    'subscribe' => [
        'app\subscribe\UserSubscribe',
    ],
];

(6)触发订阅,在业务流程中触发订阅。

<?php
/**
 * Created by PhpStorm
 * Author: fengzi
 * Date: 2023/12/15
 * Time: 17:24
 */

namespace app\admin\controller;

use think\facade\Event;

class LoginController extends AdminBaseController
{
    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
    }

    public function login()
    {
        echo "登录成功<br>";

        /**
         * 触发订阅
         * 参数1:订阅名称,名称必须要跟订阅类(UserSubscribe)中listen调用的监听名称一致
         * 参数2:传递给订阅方法的参数
         */
        $name = Event::trigger('name', ['name'=>'李四', 'age'=>30]);

        /**
         * 触发订阅
         * 参数1:订阅名称,名称必须要跟订阅类(UserSubscribe)中listen调用的监听名称一致
         * 参数2:传递给订阅方法的参数
         */
        $age = event('age', ['name'=>'王五', 'age'=>45]);

        /**
         * 打印返回数据
         * 订阅是可以返回数据的
         */
        dd($name, $age);
    }
}

(7)运行程序,展示结果。

(8)总结

简单理解:
1、事件订阅就是把订阅类中的方法当作事件来用,一个方法就是一个事件,调用订阅类中的方法就是调用事件,把相关的业务写在订阅方法中就可以了。
2、自定义订阅时,订阅类其实只是个桥梁,起到绑定具体事件类的作用。具体的业务还是写在事件类中。
3、自定义订阅中可以绑定多个事件类,每个绑定都可以取一个监听名称,业务调用时使用Event::trigger('监听名称')来调用。