前言
事件模式必须基于 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()
方法内部增加与之无关的代码。
使用场景
1、用户注册之前检查用户是否有权注册
2、用户注册成功之后发送短信、发送邮件、记录日志
这里需要定义两个事件:
1、用户注册权限检测事件BeforeUserRegister
2、用户注册事件UserRegister
还需要定义四个监听器
1、用户权限验证监听 ValidateRegisterListener.php
2、邮件发送 SendEmailListener.php
3、短信发送 SendSmsListener.php
4、记录日志 LoginEventListener.php
调用方法
EventController->test()
定义事件
<?php namespace AppEvent; /** * @property int $userId */ class UserRegister { public $userId; public function __construct($userId) { $this->userId = $userId; } }
<?php namespace AppEvent; use HyperfUtilsContext; /** * @property bool $shouldRegister */ class BeforeUserRegister { // protected $shouldRegister; public function __get($name) { // TODO: Implement __get() method. return Context::get(__CLASS__.":".$name); } public function __set($name, $value) { // TODO: Implement __set() method. return Context::set(__CLASS__.":".$name,$value); } }
定义监听器
php bin/hyperf.php gen:listener SendSmsListener php bin/hyperf.php gen:listener SendEmailListener php bin/hyperf.php gen:listener ValidateRegisterListener php bin/hyperf.php gen:listener LoginEventListener
<?php declare(strict_types=1); namespace AppListener; use AppEventBeforeUserRegister; use AppEventUserRegister; use HyperfEventAnnotationListener; use PsrContainerContainerInterface; use HyperfEventContractListenerInterface; /** * @Listener */ class LoginEventListener implements ListenerInterface { /** * @var ContainerInterface */ private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function listen(): array { return [ BeforeUserRegister::class, UserRegister::class, ]; } public function process(object $event) { if($event instanceof BeforeUserRegister){ echo get_class($event).$event->shouldRegister.PHP_EOL; }else if ($event instanceof UserRegister){ echo get_class($event).$event->userId.PHP_EOL; } } }
<?php declare(strict_types=1); namespace AppListener; use AppEventUserRegister; use HyperfEventAnnotationListener; use PsrContainerContainerInterface; use HyperfEventContractListenerInterface; /** * @Listener(priority=9) */ class SendEmailListener implements ListenerInterface { /** * @var ContainerInterface */ private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function listen(): array { return [ UserRegister::class ]; } /** * * @param UserRegister $event * @author liubo 2020-06-12 15:12 */ public function process(object $event) { echo "发送Email给".$event->userId.PHP_EOL; } }
<?php declare(strict_types=1); namespace AppListener; use AppEventUserRegister; use HyperfEventAnnotationListener; use PsrContainerContainerInterface; use HyperfEventContractListenerInterface; /** * @Listener(priority=10) */ class SendSmsListener implements ListenerInterface { /** * @var ContainerInterface */ private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function listen(): array { return [ UserRegister::class ]; } /** * * @param UserRegister $event * @author liubo 2020-06-12 15:12 */ public function process(object $event) { echo "发送短信给".$event->userId.PHP_EOL; } }
<?php declare(strict_types=1); namespace AppListener; use AppEventBeforeUserRegister; use HyperfEventAnnotationListener; use PsrContainerContainerInterface; use HyperfEventContractListenerInterface; /** * @Listener */ class ValidateRegisterListener implements ListenerInterface { /** * @var ContainerInterface */ private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function listen(): array { return [ BeforeUserRegister::class ]; } /** * * //为了调用方便此处先这样写 * @param BeforeUserRegister $event * @author liubo 2020-06-12 15:27 */ public function process(object $event) { $event->shouldRegister = (bool)rand(0,1); if(!$event->shouldRegister){ echo "很抱歉,您无权注册!".PHP_EOL; }else{ echo "欢迎注册!".PHP_EOL; } } }
使用示例
<?php namespace AppController; use AppServiceUserService; use HyperfDiAnnotationInject; use HyperfHttpServerAnnotationAutoController; /** * @AutoController() */ class EventController extends AbstractController { /** * @Inject() * @var UserService */ private $userService; public function test(){ return $this->userService->register(); } }
<?php namespace AppService; use AppEventBeforeUserRegister; use AppEventUserRegister; use HyperfDiAnnotationInject; use PsrEventDispatcherEventDispatcherInterface; class UserService { /** * @Inject() * @var EventDispatcherInterface */ private $eventDispatcher; public function register() { //验证是否有注册权限 $beforeUserRegister=new BeforeUserRegister(); $this->eventDispatcher->dispatch(new BeforeUserRegister()); if($beforeUserRegister->shouldRegister){ //注册用户 $userId =rand(0,9999); //注册成功后 $this->eventDispatcher->dispatch(new UserRegister($userId)); return $userId; }else{ return "不可注册!"; } } }
运行结果
欢迎注册! AppEventBeforeUserRegister1 发送短信给6195 发送Email给6195 AppEventUserRegister6195