一、序章

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('监听名称')来调用。

ThinkPHP6 事件的简单应用的更多相关文章

  1. Unity 游戏框架搭建 2019 (四十八/四十九) MonoBehaviourSimplify 中的消息策略完善&关于发送事件的简单封装

    MonoBehaviourSimplify 中的消息策略完善 在上一篇,笔者说,MonoBehaviourSimplify 中的消息策略还有一些小问题.我们在这篇试着解决一下. 先贴出来代码: usi ...

  2. C#委托与事件的简单使用

    前言:上一篇博文从原理和定义的角度介绍了C#的委托和事件.本文通过一个简单的小故事,来说明C#委托与事件的使用方法及其方便之处. 在阅读本文之前,需要你对委托和事件的基本概念有所了解.如果你是初次接触 ...

  3. JavaScript使用自定义事件实现简单的模块化开发

    WEB前端最常见驱动方式就是事件了, 所有交互等等都是通过事件,前端的常见事件有: UI事件: 焦点事件: 鼠标事件: 滚轮事件: 文本事件: 键盘事件: 变动事件: 现在网页上有一个输入框, 如果我 ...

  4. jQuery下ajax事件的简单分析

    昨天写了一篇关于监视页面动态生成元素问题的文章,引起了一些小小的争议,不过我从中学到了很多.文章在这,<jQuery下实现等待指定元素加载完毕>当然 动态生成的节点元素 分很多种情况,这里 ...

  5. js粘贴事件paste简单解析及遇到的坑

    在用户执行粘贴操作的时候,js能够获得剪切板的内容,本文讨论一下这个问题. 目前只有Chrome支持获取剪切板中的图片数据.还好需要这个功能的产品目前只支持Chrome和Safari,一些Chrome ...

  6. C# 委托和事件,简单示例说明问题

    先看看示例效果 按照国际惯例,得先说说概念. 委托(C# 编程指南) 事件(C# 编程指南) 以上内容来自MSDN. 委托源码 [委托] 概念和代码都有了.剩下的就是应用了,要是只知道概念不会用,那还 ...

  7. 对C#中事件的简单理解

    对于C#中的事件,我举了个简单的例子来理解事件及其处理. 这个例子中母亲是事件的发布者,事件是吃饭了.儿子和父亲是事件的订阅者,各自的Eat方法是处理事件的方法. 下面是详细的加注的例子: using ...

  8. JavaScript----DOM和事件的简单学习

    ##DOM简单学习 *  功能:控制html文档的内容 *  代码:获取页面标签(元素)对象:Element *  document.getElementById("id值"):通 ...

  9. C#自定义事件(简单版本)

    C#中的事件分为两种:一种是厂商微软在VS中已经内置,以供用户使用:另一种是有用户自己定义的事件: 先简单回顾下第一种: [场景1]一个Form上一个Textbox控件和Button控件,当用户按下B ...

  10. 实际项目中积累的一些关于事件的简单应用JS代码段(能力有限,不喜轻喷,23333)

    1:鼠标移入移出显示另一张图片 var yuanquan_1 = document.getElementById("yuanquan_1" );  yuanquan_1. onmo ...

随机推荐

  1. C# await和Result对比

    1.Result 上图是微软官网的截图,由图可知在使用GetXXXX的方法的时候,会阻塞调用其他线程,直到当前异步操作完成,相当于调用wait方法.但是使用异步编程应该避免使用TASK.WAIT或TA ...

  2. 2024-01-31:用go语言,机器人正在玩一个古老的基于DOS的游戏, 游戏中有N+1座建筑,从0到N编号,从左到右排列, 编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位, 起

    2024-01-31:用go语言,机器人正在玩一个古老的基于DOS的游戏, 游戏中有N+1座建筑,从0到N编号,从左到右排列, 编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位, 起 ...

  3. 关于DbgridEh滚动从表一起跟着滚动的分析

    我的实现:

  4. 《ASP.ENT Core 与 RESTful API 开发实战》(第3章)-- 读书笔记(上)

    第 3 章 ASP.NET Core 核心特性 3.1 启动与宿主 ASP.NET Core 应用程序启动时,它首先会配置并运行其宿主,宿主主要用来启动.初始化应用程序,并管理其生命周期 ASP.NE ...

  5. Codeforces Round #887 (Div. 2) A-D

    比赛链接 A 代码 #include <bits/stdc++.h> using namespace std; using ll = long long; int a[507]; bool ...

  6. NC19975 [HAOI2008]移动玩具

    题目链接 题目 题目描述 在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移 ...

  7. UVA11573 Ocean Currents

    题目链接 题目 见链接. 题解 知识点:BFS. 这道题显然用BFS,但发现洋流方向会破坏时间的有序性,但注意到洋流时间花费是 \(0\) ,因此只需要用双端队列即可,洋流方向扩展直接放队头,其他方向 ...

  8. Python def() 后的-> 符号的作用

    python – 定义函数 def 后面的 ->,:表示的含义-> 常常出现在python函数定义的函数名后面,为函数添加元数据,描述函数返回的类型. : 表示参数的类型建议符示例: de ...

  9. 【分布式】load balance 03-一致性哈希算法 java 实现

    负载均衡系列专题 01-负载均衡基础知识 02-一致性 hash 原理 03-一致性哈希算法 java 实现 04-负载均衡算法 java 实现 本节我们来看一下如何实现一个一致性 hash 框架. ...

  10. 【OpenGL ES】凸镜贴图

    1 前言 ​ 正方形图片贴到圆形上 中将正方形图片上的纹理映射到圆形模型上,同理,也可以将圆形上的纹理映射到凸镜的球形曲面上.如下图,最左边的竖条是原图片的截面(纹理坐标),最右边的竖条是变换后的顶点 ...