Hyperf 事件機制


前言

事件模式必須基於 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 App\Event;
/**
 * @property int $userId
 */
class UserRegister
{
    public $userId;
    public function __construct($userId)
    {
        $this->userId = $userId;
    }
}
<?php
namespace App\Event;
use Hyperf\Utils\Context;

/**
 * @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 App\Listener;

use App\Event\BeforeUserRegister;
use App\Event\UserRegister;
use Hyperf\Event\Annotation\Listener;
use Psr\Container\ContainerInterface;
use Hyperf\Event\Contract\ListenerInterface;

/**
 * @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 App\Listener;

use App\Event\UserRegister;
use Hyperf\Event\Annotation\Listener;
use Psr\Container\ContainerInterface;
use Hyperf\Event\Contract\ListenerInterface;

/**
 * @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 App\Listener;

use App\Event\UserRegister;
use Hyperf\Event\Annotation\Listener;
use Psr\Container\ContainerInterface;
use Hyperf\Event\Contract\ListenerInterface;

/**
 * @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 App\Listener;

use App\Event\BeforeUserRegister;
use Hyperf\Event\Annotation\Listener;
use Psr\Container\ContainerInterface;
use Hyperf\Event\Contract\ListenerInterface;

/**
 * @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 App\Controller;
use App\Service\UserService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;

/**
 * @AutoController()
 */
class EventController extends AbstractController
{
    /**
     * @Inject()
     * @var UserService
     */
    private $userService;

    public function test(){
        return $this->userService->register();
    }

}

 

<?php


namespace App\Service;


use App\Event\BeforeUserRegister;
use App\Event\UserRegister;
use Hyperf\Di\Annotation\Inject;
use Psr\EventDispatcher\EventDispatcherInterface;

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 "不可注冊!";
        }
    }

}

 

運行結果

歡迎注冊!
App\Event\BeforeUserRegister1
發送短信給6195
發送Email給6195
App\Event\UserRegister6195

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM