laravel queue-event 实现
27 September 2018

laravel 在处理 event listeners 的时候会有如下操作

foreach ((array) $events as $event) {
    // ...
    $this->listeners[$event][] = $this->makeListener($listener);
}

makeListener 即创建 listener,listener 是一个函数,该函数接收 (event, payload) 这两个参数
在创建 listener 的时候会进行判断如果这个 listener implements ShouldQueue

public function makeListener($listener, $wildcard = false)
{
    if (is_string($listener)) {
        return $this->createClassListener($listener, $wildcard);
    }

    // ...
}

public function createClassListener($listener, $wildcard = false)
{
    return function ($event, $payload) use ($listener, $wildcard) {
        if ($wildcard) {
            return call_user_func($this->createClassCallable($listener), $event, $payload);
        }

        return call_user_func_array(
            $this->createClassCallable($listener), $payload
        );
    };
}

protected function createClassCallable($listener)
{
    list($class, $method) = $this->parseClassCallable($listener);

    if ($this->handlerShouldBeQueued($class)) {
        return $this->createQueuedHandlerCallable($class, $method);
    }

    return [$this->container->make($class), $method];
}

protected function createQueuedHandlerCallable($class, $method)
{
    return function () use ($class, $method) {
        $arguments = array_map(function ($a) {
            return is_object($a) ? clone $a : $a;
        }, func_get_args());

        // ...
        $this->queueHandler($class, $method, $arguments);
    };
}

protected function queueHandler($class, $method, $arguments)
{
    list($listener, $job) = $this->createListenerAndJob($class, $method, $arguments);

    $connection = $this->resolveQueue()->connection(
        $listener->connection ?? null
    );

    $queue = $listener->queue ?? null;

    isset($listener->delay)
        ? $connection->laterOn($queue, $listener->delay, $job)
        : $connection->pushOn($queue, $job);
}

上面是创建完定制好的 listener,下面是 dispatch 的时候会触发的操作

foreach ($this->getListeners($event) as $listener) {
    $response = $listener($event, $payload);

    // ...
}