Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

11. 事件机制 #11

Open
xiaohuilam opened this issue Sep 27, 2018 · 0 comments
Open

11. 事件机制 #11

xiaohuilam opened this issue Sep 27, 2018 · 0 comments
Labels
book The digital book for laravel learning

Comments

@xiaohuilam
Copy link
Owner

xiaohuilam commented Sep 27, 2018

根据 Laravel 的 Events 文档 (中文版:事件系统), EventServiceProvider 的使用方法为:

/**
 * 注册应用中的其它事件。
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Event::listen('event.name', function ($foo, $bar) {
        //
    });
}

如果花点时间研究 Event 这个 Facade,我们可以找到他穿透类其实为 Illuminate\Events\Dispatcher

Illuminate\Events\Dispatcher 类的 __construct 方法为:

public function __construct(ContainerContract $container = null)
{
$this->container = $container ?: new Container;
}

作用是将容器设置到 $this->container 属性

监听

我们刚刚在 EventServiceProvider 调用的 Event::listen 方法的代码为:

public function listen($events, $listener)
{
foreach ((array) $events as $event) {
if (Str::contains($event, '*')) {
$this->setupWildcardListen($event, $listener);
} else {
$this->listeners[$event][] = $this->makeListener($listener);
}
}
}

如果监听了通配事件,setupWildcardListen 在辗转后跟 else 一样的调用到了 makeListener

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

注意,返回的是闭包!并不会立即执行。

在存放到 $this->listeners 后,事件们就静静地等待被触发

$this->listeners[$event][] = $this->makeListener($listener);

触发

在我们调用 event() 辅助方法后,触发的逻辑其实走到了 dispatch 方法

public function dispatch($event, $payload = [], $halt = false)
{
// When the given "event" is actually an object we will assume it is an event
// object and use the class as the event name and this event itself as the
// payload to the handler, which makes object based events quite simple.
list($event, $payload) = $this->parseEventAndPayload(
$event, $payload
);
if ($this->shouldBroadcast($payload)) {
$this->broadcastEvent($payload[0]);
}
$responses = [];
foreach ($this->getListeners($event) as $listener) {
$response = $listener($event, $payload);
// If a response is returned from the listener and event halting is enabled
// we will just return this response, and not call the rest of the event
// listeners. Otherwise we will add the response on the response list.
if ($halt && ! is_null($response)) {
return $response;
}
// If a boolean false is returned from a listener, we will stop propagating
// the event to any further listeners down in the chain, else we keep on
// looping through the listeners and firing every one in our sequence.
if ($response === false) {
break;
}
$responses[] = $response;
}
return $halt ? null : $responses;
}

核心逻辑就这句:

$response = $listener($event, $payload);

@xiaohuilam xiaohuilam changed the title 11. 事件机制 [0%] 11. 事件机制 Sep 29, 2018
@xiaohuilam xiaohuilam added the book The digital book for laravel learning label Sep 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
book The digital book for laravel learning
Projects
None yet
Development

No branches or pull requests

1 participant