事件机制
事件模式必须基于 PSR-14 去实现。 Hyperf 的事件管理器默认由 hyperf/event 实现,该组件亦可用于其它框架或应用,只需通过 Composer 将该组件引入即可。
composer require hyperf/event
概念
事件模式是一种经过了充分测试的可靠机制,是一种非常适用于解耦的机制,分别存在以下 3 种角色:
事件(Event) 是传递于应用代码与 监听器(Listener) 之间的通讯对象
监听器(Listener) 是用于监听 事件(Event) 的发生的监听对象
事件调度器(EventDispatcher) 是用于触发 事件(Event) 和管理 监听器(Listener) 与 事件(Event) 之间的关系的管理者对象
用通俗易懂的例子来说明就是,假设我们存在一个 UserService::register() 方法用于注册一个账号,在账号注册成功后我们可以通过事件调度器触发 UserRegistered 事件,由监听器监听该事件的发生,在触发时进行某些操作,比如发送用户注册成功短信,在业务发展的同时我们可能会希望在用户注册成功之后做更多的事情,比如发送用户注册成功的邮件等等,此时我们就可以通过再增加一个监听器监听 UserRegistered 事件即可,无需在 UserService::register() 方法内部增加与之无关的代码。
使用事件管理器
接下来我们会通过配置和注解两种方式介绍监听器,实际使用时,二者只需使用其一即可,如果既有注解又有配置,则会造成监听器被多次触发。
定义一个事件
一个事件其实就是一个用于管理状态数据的普通类,触发时将应用数据传递到事件里,然后监听器对事件类进行操作,一个事件可被多个监听器监听。
// App/Event/UserRegistered.php
<?php namespace App\Event; class UserRegistered { // 建议这里定义成 public 属性,以便监听器对该属性的直接使用,或者你提供该属性的 Getter public $user; public function __construct($user) { $this->user = $user; } }
定义一个监听器
监听器都需要实现一下 Hyperf\Event\Contract\ListenerInterface 接口的约束方法,示例如下。
// App/Listener/UserRegisteredListener.php
<?php namespace App\Listener; use App\Event\UserRegistered; use Hyperf\Event\Contract\ListenerInterface; class UserRegisteredListener implements ListenerInterface { public function listen(): array { // 返回一个该监听器要监听的事件数组,可以同时监听多个事件 return [ UserRegistered::class, ]; } /** * @param UserRegistered $event */ public function process(object $event): void { // 事件触发后该监听器要执行的代码写在这里,比如该示例下的发送用户注册成功短信等 // 直接访问 $event 的 user 属性获得事件触发时传递的参数值 // $event->user; // 此处是事件触发后的业务逻辑处理 echo '用户注册事件触发,我执行了, 用户 ID:' . $event->user->id; var_dump($event->user); } }
通过配置文件注册监听器
在定义完监听器之后,我们需要让其能被 事件调度器(Dispatcher) 发现,可以在 config/autoload/listeners.php 配置文件 (如不存在可自行创建) 内添加该监听器即可,监听器的触发顺序根据该配置文件的配置顺序:
<?php return [ \App\Listener\UserRegisteredListener::class, ];
触发事件-事件调度器分发事件
事件需要通过 事件调度器(EventDispatcher) 调度才能让 监听器(Listener) 监听到,
此处我在控制器进行事件调度。可以在其他位置进行事件调度,如 UserService 层。
我们通过一段代码来演示如何触发事件:
<?php namespace App\Controller; use App\Event\UserRegistered; use App\Model\User; use Hyperf\Di\Annotation\Inject; use Psr\EventDispatcher\EventDispatcherInterface; class TestListController { /** * @var EventDispatcherInterface */ #[Inject] private $eventDispatcher; public function index(){ $user = new User(); $user->name = 'John'; $user->gender = 1; $user->created_at = time(); $user->updated_at = time(); $result = $user->save(); // 完成账号注册的逻辑 // 这里 dispatch(object $event) 会逐个运行监听该事件的监听器 $this->eventDispatcher->dispatch(new UserRegistered($user)); return $result; } }
新建一个模型层
// App/Model/User.php
<?php namespace App\Model; use Hyperf\DbConnection\Model\Model; /** * @property $id * @property $name * @property $gender * @property $created_at * @property $updated_at */ class User extends Model { /** * The table associated with the model. * * @var string */ protected ?string $table = 'user'; public bool $timestamps = false; /** * The attributes that are mass assignable. * * @var array */ protected array $fillable = ['id', 'name', 'gender', 'created_at', 'updated_at']; /** * The attributes that should be cast to native types. * * @var array */ protected array $casts = ['id' => 'integer', 'gender' => 'integer']; }
window docker容器Hyperf3.1 框架连接宿主机Mysql
1、查看本机ip
ipconfig
2、修改.env,使用该ip进行连接
APP_NAME=skeleton APP_ENV=dev DB_DRIVER=mysql DB_HOST=192.168.3.50 DB_PORT=3306 DB_DATABASE=hyperf DB_USERNAME=root DB_PASSWORD=root DB_CHARSET=utf8mb4 DB_COLLATION=utf8mb4_unicode_ci DB_PREFIX= REDIS_HOST=192.168.3.50 REDIS_AUTH=null REDIS_PORT=6380 REDIS_DB=0 REDIS_DB2=1
3、本地使用Navicat连接 小皮集成环境的MySQL服务
4、如果连接不上,需要修改数据库的连接权限
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; Query OK, 0 rows affected (0.00 sec) mysql> flush privileges; Query OK, 0 rows affected (0.01 sec) mysql>
其中各字符的含义:
1)、*.* 对任意数据库任意表有效
2)、"root" "root" 是数据库用户名和密码
3)、'%' 允许访问数据库的IP地址,%意思是任意IP,也可以指定IP
4)、flush privileges 刷新权限信息
参考:
本文为崔凯原创文章,转载无需和我联系,但请注明来自冷暖自知一抹茶ckhttp://www.cksite.cn