欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

Laravel事件 event 有大用

概述

事件是一种常见的观察者模式的应用。简单的来说,就是当...干...。这个当...和干...在Laravel 事件中分别对应:
当(event)...干(listener)...
放置event和listener文件的位置分别是:
app/Events
app/Listeners

对于产品经理来说,事件主要用来规范你的业务逻辑,使支线逻辑与主线逻辑独立分拆。对于程序员来说,事件可以让Controller变得非常简洁,解耦,可维护。

定义事件(Event)

用Artisan命令可以快速生成一个模板:
php artisan event:generate

  1. <?php

  2. namespace App\Events;

  3. use App\Podcast;

  4. use App\Events\Event;

  5. use Illuminate\Queue\SerializesModels;

  6. class PodcastWasPurchased extends Event

  7. {

  8.    use SerializesModels;

  9.    public $podcast;

  10.    /**

  11.     * Create a new event instance.

  12.     *

  13.     * @param  Podcast  $podcast

  14.     * @return void

  15.     */

  16.    public function __construct(Podcast $podcast)

  17.    {

  18.        $this->podcast = $podcast;

  19.    }

  20. }

这样就定义了一个事件,这个事件里没有任何业务逻辑,就是一个数据传输层DTL(Data Transpotation Layer),记住这个概念,在很多设计模式中都需要涉及到。

定义事件的侦听和处理器(Listener and Handler)

你在用artisan命令生成Event的时候,对应的Listner也一并生成好了:

  1. <?php

  2. namespace App\Listeners;

  3. use App\Events\PodcastWasPurchased;

  4. use Illuminate\Queue\InteractsWithQueue;

  5. use Illuminate\Contracts\Queue\ShouldQueue;

  6. class EmailPurchaseConfirmation

  7. {

  8.    /**

  9.     * Create the event listener.

  10.     *

  11.     * @return void

  12.     */

  13.    public function __construct()

  14.    {

  15.        //

  16.    }

  17.    /**

  18.     * Handle the event.

  19.     *

  20.     * @param  PodcastWasPurchased  $event

  21.     * @return void

  22.     */

  23.    public function handle(PodcastWasPurchased $event)

  24.    {

  25.        // Access the podcast using $event->podcast...

  26.    }

  27. }

handler里就是写业务逻辑的地方了,这里可以用type-hint依赖注入的方式,注入任何你需要的类。

将Event和Listener绑定并注册

这里就用到Service Provider: providers/EventServiceProvider.php 注册事件和Listener:

  1. protected $listen = [

  2.    'App\Events\PodcastWasPurchased' => [

  3.        'App\Listeners\EmailPurchaseConfirmation',

  4.    ],

  5. ];

触发事件

经过上面的设置,你的事件和事件处理器就可以在controller里使用了:

  1. <?php

  2. namespace App\Http\Controllers;

  3. use Event;

  4. use App\Podcast;

  5. use App\Events\PodcastWasPurchased;

  6. use App\Http\Controllers\Controller;

  7. class UserController extends Controller

  8. {

  9.    /**

  10.     * Show the profile for the given user.

  11.     *

  12.     * @param  int  $userId

  13.     * @param  int  $podcastId

  14.     * @return Response

  15.     */

  16.    public function purchasePodcast($userId, $podcastId)

  17.    {

  18.        $podcast = Podcast::findOrFail($podcastId);

  19.        // Purchase podcast logic...

  20.        Event::fire(new PodcastWasPurchased($podcast));

  21.    }

  22. }

Event::fire(new PodcastWasPurchased($podcast));就是触发事件的写法,程序运行到这里,就会触发跟这个事件绑定的listener(handler)。
Event::fire()有个辅助函数可以简写:

  1. event(new PodcastWasPurchased($podcast));

将事件加入队列

如果要处理的事件很多,那么会影响当前进程的执行效率,这时我们需要把事件加入队列,让它延迟异步执行。

定义队列执行是在Listener那里定义的:

  1. <?php

  2. namespace App\Listeners;

  3. use App\Events\PodcastWasPurchased;

  4. use Illuminate\Queue\InteractsWithQueue;

  5. use Illuminate\Contracts\Queue\ShouldQueue;

  6. class EmailPurchaseConfirmation implements ShouldQueue

  7. {

  8.    //

  9. }

只要implements ShouldQueue一下就好了。

如果你想手动指定一下任务延迟执行的时间:

  1. <?php

  2. namespace App\Listeners;

  3. use App\Events\PodcastWasPurchased;

  4. use Illuminate\Queue\InteractsWithQueue;

  5. use Illuminate\Contracts\Queue\ShouldQueue;

  6. class EmailPurchaseConfirmation implements ShouldQueue

  7. {

  8.    use InteractsWithQueue;

  9.    public function handle(PodcastWasPurchased $event)

  10.    {

  11.        if (true) {

  12.            $this->release(10);

  13.        }

  14.    }

  15. }

触发后延迟10秒执行。

事件订阅(Event Subscribers)

Event Subscribers是一种特殊的Listener,前面讲的是一个listener里只能放一个hander(),事件订阅可以把很多处理器(handler)放到一个类里面,然后用一个listner把它们集合起来,这样不同的事件只要对应一个listner就可以了。

  1. <?php

  2. namespace App\Listeners;

  3. class UserEventListener

  4. {

  5.    /**

  6.     * Handle user login events.

  7.     */

  8.    public function onUserLogin($event) {}

  9.    /**

  10.     * Handle user logout events.

  11.     */

  12.    public function onUserLogout($event) {}

  13.    /**

  14.     * Register the listeners for the subscriber.

  15.     *

  16.     * @param  Illuminate\Events\Dispatcher  $events

  17.     * @return array

  18.     */

  19.    public function subscribe($events)

  20.    {

  21.        $events->listen(

  22.            'App\Events\UserLoggedIn',

  23.            'App\Listeners\UserEventListener@onUserLogin'

  24.        );

  25.        $events->listen(

  26.            'App\Events\UserLoggedOut',

  27.            'App\Listeners\UserEventListener@onUserLogout'

  28.        );

  29.    }

  30. }

看后面的subscribe(),每个事件和处理器是一一对应的。

绑定 Event Subscriber到Service Provider

  1. <?php

  2. namespace App\Providers;

  3. use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;

  4. use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

  5. class EventServiceProvider extends ServiceProvider

  6. {

  7.    /**

  8.     * The event listener mappings for the application.

  9.     *

  10.     * @var array

  11.     */

  12.    protected $listen = [

  13.        //

  14.    ];

  15.    /**

  16.     * The subscriber classes to register.

  17.     *

  18.     * @var array

  19.     */

  20.    protected $subscribe = [

  21.        'App\Listeners\UserEventListener',

  22.    ];

  23. }

究竟为什么要使用Event

使用Event一段时间后,你可以觉得比较麻烦,想知道到底有什么好处。
假设创建一个类 Event, 那么$event->sendWelcomeMessage($user) 这样去使用, 和用观察者模式的事件有啥区别,观察者模式好处在哪里?

首先你要明白,事件是一种『钩子』,Fire事件的位置就是放置钩子的地方。而上面那种写法是直接嵌入的,没有钩子,也就是说,上面的写法没有事件的概念,事件是不用管你怎么做的,事件只定义发生了什么事(当...时),这样就可以解耦。

区别就在于,在主逻辑线上的事件,没有做任何事情,它只是说有这样一件事,对于这件事,你可以做点事情,也可以什么都不做。而$event->sendWelcomeMessage($user)这种写法就是hardcoding了,到了那个地方必须发生sendWelcomeMessage这个行为。

作为团队的一个leader,你可以把主逻辑定义后,然后在主逻辑线上设计事件节点,然后把具体怎么处理这些事件的事务交给团队里的成员去做,成员根本不用管主逻辑和插入事件(钩子)的地方,成员只用写触发事件时要处理的逻辑就可以了。

这样是不是很方便合理啊,如果把所有处理逻辑都写在Event类里面,那多人处理的时候岂不是要同时修改一个文件,这样就会有版本冲突问题。

另外Event还可以异步队列执行,这也是好处之一。


来自   https://blog.csdn.net/zhaoxuejie/article/details/52809038

普通分类: