Laravel 提供的 Bus 总线组件主要为了解决什么问题?我们平时使用的 event、dispatch 等方法和他有什么关系?他和 Event 组件提供的 Dispatcher 有什么区别?
Bus 总线和 Event 的组件都提供了 Dispatcher 服务,但主要区别如下:
- Bus 总线提供的 Dispatcher 可以 dispatch 任何 command
- Event 组件提供的 Dispatcher 只能 dispatch 已经注册的 event
- 都提供了 dispatch new 和 dispatch to queue 的支持
EventDispatcher dispatch 的 event 若事先未注册,则不会有任何反应。
Bus Dispatcher
完整应用了 管道流的原理,可以将任意的 command 对象通过该总线发射出去。
$busDispatcher->pipeThrough($piples)->dispatch($command);
如下面的例子,用户注册成功后,通过一系列的检查操作后,发送邮件。
app('Illuminate\Contracts\Bus\Dispatcher')->pipeThrough([
'Check1', 'Check2', 'Check3'
])->dispatch($user);
// need have `handler` method.
class User
{
public function handle()
{
// send email.
}
}
如果上面的 command 实现自 ShouldQueue,那么发送邮件这一步操作将会放到队列中去执行。
⏰ 此处的 handle 方法参数可自动注入你想要的任何对象。
通常我们不会将「处理器」和 command 放在同一个类中,可以通过下面的方式指定单独的处理类(发送邮件)。
手动指定处理器后, handle 方法不可在自动注入参数。
app('Illuminate\Contracts\Bus\Dispatcher')->pipeThrough([
'Check1', 'Check2', 'Check3'
])->map([
'App\User' => 'App\SendEmailHandler'
])->dispatch($user);
class SendEmailHandler
{
public function handle(User $user)
{
// send emial for user.
}
}
也可以直接调用 dispatchNow 来立即发送,这种发式无论 command 是否实现自 ShouldQueue,都不会经过队列;并且你还可以指定额外的处理器来覆盖默认的处理操作。
app('Illuminate\Contracts\Bus\Dispatcher')->pipeThrough([
'Check1', 'Check2', 'Check3'
])->dispatchNow($user, new \App\SendReadpackHandler);
Laravel 还为我们提供了一个叫做 PendingDispatch 的类,用来「延迟」具体的 dispatch 操作。其原理和 Bus Dispatcher 一样,只是利用 PHP 的 __destruct 当对象引用被销毁或程序退出时再执行真正的 dispatch 操作。
public function __destruct()
{
app(Dispatcher::class)->dispatch($this->job);
}
所以若你直接在命令行执行如下的代码,其实是没有任何输出的;但当你将其赋空时,程序将会正常执行。
✗ tinker
Psy Shell v0.9.9 (PHP 7.3.14 — cli) by Justin Hileman
>>>
>>> $dispatch = dispatch(new \App\Jobs\SendEmail('send email to lianbo'))
=> Illuminate\Foundation\Bus\PendingDispatch {#3076}
>>>
>>> $dispatch = null
Ok, received
=> null
Event Dispatcher
Event 组件提供的 dispatch 只能转发已经注册到事件服务上的 event,如下所示:
Event::listen($eventName, $listener);
$eventDispatcher->dispatch($eventName); // ok
$eventDispatcher->dispatch($otherName); // null
所以我们经常使用 event($eventName)
来发射事件。
总的来说,Event Dispatcher 的功能远不如 Bus 组件那么强大,Bus Dispatcher 基于 Laravel 强大的 Container,我们可以 dispatch 任何对象并自动注入我们需要的依赖。