[译]Laravel 5.0 之事件及处理程序

本文译自 Matt Stauffer系列文章.


提示:如果你还没有看过 Laravel 5.0 之命令及处理程序 这篇文章,建议先看一下。它包括了本文所需的背景知识。

借助 Laravel 5 的命令(及命令处理程序),你可以通过封装的方式非常简单、直接地向系统发出命令。DoThis.HandleACommandThatIsTellingMeToDoThis, 它是命令式的,告诉系统要做什么事。

但有时候,不管是在命令结果中,还是在其它的上下文中,我们需要发出更抽象的通知。比如在 Laravel 4 中,可以直接以事件名称的字符串来触发事件(而不是像上面那样通过对象和方法):

$response = Event::fire('auth.login', array($user));

这行代码向整个应用发出一条通知:“有人登陆了,这是用户信息”。它是知会式的,只是知会事件发生比提供相关信息。如果你熟悉“发布/订阅”概念的话,这就是“事件”机制要处理的。

在 Laravel 5 中,事件系统已经得到了升级,看上去与上一篇文章中介绍过的命令系统有几分相似。在升级后的事件系统中,不是基于字符串来标识事件(比如 "auth.login"),而是创建一个 PHP 对象,并发布它。

示例

接下来,直接以例子来做说明:

生成事件

$ php artisan make:event ThingWasDone

... 这行命令会生成下面的代码:

namespace SaveMyProposals\Events;

use SaveMyProposals\Events\Event;

use Illuminate\Queue\SerializesModels;

class ThingWasDone extends Event {

    use SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

}

你可以给构造函数添加参数并把参数值绑定到类的属性值,通过这样的方式为这个类提供额外的数据。

生成事件处理程序

执行命令:

$ php artisan handler:event SendMailInSomeParticularContext --event="ThingWasDone"

这行代码会生成下面的代码:

namespace SaveMyProposals\Handlers\Events;

use SaveMyProposals\Events\ThingWasDone;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;

class SendMailInSomeParticularContext {

    /**
     * Create the event handler.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  ThingWasDone  $event
     * @return void
     */
    public function handle(ThingWasDone $event)
    {
        //
    }

}

需要注意的一点是,生成的代码中,已经为 handle 方法指定了一个带有类型约束的 ThingWasDone $event 参数。不管是构造函数还是 event 方法,你都可以借助依赖注入来提供任何你需要的工具或对象。

绑定事件

在上一个步骤中我们创建了一个事件及其处理程序,但仅仅是创建,并没有通知事件总线(bus)我们刚才创建的事件和处理程序是配对的。所以接下来还需要在 app\Providers\EventServiceProvider 中绑定它们的监听关系,可以在 $listen 属性中做这件事:

// app\Providers\EventServiceProvider
    $listen = [
        ThingWasDone::class => [
            SendMailInSomeParticularContext::class,
            SaveSomeRecordInSomeOtherContext::class,
            DoSomethingElseInResponseToThingBeingDone::class
        ]
    ];

如你所见,通过 ::class 得到一个代表事件类名的字符串作为 key,然后在值数组中添加监听器(也是通过 ::class)。

“预备...瞄准...开火(::fire)”

好了,一切准备就绪,接下来就是触发该事件了。要注意的是这里只有简单的 PHP 类,所以你可以手动实例化事件,实例化事件对应的处理程序,然后把事件传递给处理程序。但那当然不是 Laravel 的思路, Laravel 提供了事件总线让以上这一系列的工作更简单,更具有一致性和全局性:

\Event::fire(new ThingWasDone($param1, $param2));

就这么简单!

ShouldBeQueued

与命令系统的机制一样,你可以让你的事件实现 Illuminate\Contracts\Queue\ShouldBeQueued 接口,从而使事件处理程序被加入到队列中异步执行;也可以给你的事件处理程序加上 Illuminate\Queue\InteractsWithQueue 的 trait,使事件处理程序的 handle 方法变得容易从外部访问,从而使事件处理程序可以和事件队列进行交互。比如在队列中删除当前的任务。

SerializesModels trait

还是与命令一样的,如果你需要在事件中用到某个 Eloquent 模型,你可以在事件类的代码顶部包含 SerializesModels 这个 trait。在本文写作时,生成的时间代码实际上已经默认包含了这部分。

写在最后

就这么多了。只要你理解了 Laravel 5 的命令和处理程序,掌握事件处理机制就是一件非常容易的事了。触发系统向整个应用发出通知说某个事件发生了,而不是要求系统执行某些操作。但本质上它们都是封装的信息和目的。它们可以互相配合使用,结果会更棒!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

goroutine背后的系统知识

Go语言从诞生到普及已经三年了,先行者大都是Web开发的背景,也有了一些普及型的书籍,可系统开发背景的人在学习这些书籍的时候,总有语焉不详的感觉,网上也有若干...

3518
来自专栏和蔼的张星的图像处理专栏

1.Win10+VsCode的C/CPP编译环境搭建

我是从开始学C++的时候就一直用的是visual studio,毕竟宇宙第一IDE,写和调试都是超级方便快捷,唯一的缺点可能就是启动慢一点。 之前电脑没有换固...

8336
来自专栏Golang语言社区

goroutine背后的系统知识

Go语言从诞生到普及已经三年了,先行者大都是Web开发的背景,也有了一些普及型的书籍,可系统开发背景的人在学习这些书籍的时候,总有语焉不详的感觉,网上也有若干流...

2855
来自专栏Golang语言社区

goroutine背后的系统知识

Go语言从诞生到普及已经三年了,先行者大都是Web开发的背景,也有了一些普及型的书籍,可系统开发背景的人在学习这些书籍的时候,总有语焉不详的感觉,网上也有若干流...

3514
来自专栏JavaEdge

大道缓存1 缓存特征2 缓存介质3 缓存分类和应用场景缓存实战

用户请求从界面(浏览器/App)到网络转发、应用服务再到存储(数据库或文件系统),然后返回到界面呈现内容。

1211
来自专栏程序员互动联盟

【专业技术】linux下socket编程

1. 网络中进程之间如何通信 进程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作...

3326
来自专栏Laoqi's Linux运维专列

日常shell练习题-03(持续更新…)

2693
来自专栏代码世界

Python之进程

进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机...

6547
来自专栏Java架构师学习

学习分布式系统限流、降级、熔断框架就要看这篇文章为什么需要HystrixHystrix如何解决依赖隔离如何使用HystrixHystrix关键组件分析

9685
来自专栏Puppeteer学习

一步一步学Vue(七)

1673

扫码关注云+社区

领取腾讯云代金券