Laravel 框架的事件处理机制是通过类EventServiceProvider来实现的.
建立事件
首先我需要将自己的事件和监听者注册到app\Providers目录下的EventServiceProvider类中的$listen数组中
然后运行php artisan event:generate 命令会自动生成相应的事件类和监听者类。然后在相应的类中编写事件的逻辑和监听者的逻辑。调用事件可以使用 Event:: fire(new App\Events\TestEvent()) .这就是调用事件的基本步骤。具体请参考官方文档。
事件触发前
在服务提供者中,一般有register和boot方法,而boot方法一般在框架中已经注册完所有的服务提供者之后运行。而app\Providers目录下的EventServiceProvider类中的boot方法继承父类的boot方法。于是我们查看父类的boot方法如下:
- public function boot()
- {
- foreach ($this->listens() as $event => $listeners) {
- foreach ($listeners as $listener) {
- Event::listen($event, $listener);
- }
- }
- foreach ($this->subscribe as $subscriber) {
- Event::subscribe($subscriber);
- }
- }
- 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);
- }
- }
- }
- $this->listeners[$event][] = $this->makeListener($listener);
- 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);
- } else {
- return $listener(...array_values($payload));
- }
- };
- }
- 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);
- } else {
- return call_user_func_array(
- $this->createClassCallable($listener), $payload
- );
- }
- };
- }
- return call_user_func_array(
- $this->createClassCallable($listener), $payload
- );
- $this->createClassCallable($listener)
总结:在boot方法中实现事件监听者的注册与事件的绑定,而在注册与绑定过程中,将会封装一个闭包,并且在闭包中实现调用事件监听者类中的handle方法。
事件触发
事件触发采用如下形式:
- Event::fire(new TestEvent());
- public function fire($event, $payload = [], $halt = false)
- {
- return $this->dispatch($event, $payload, $halt);
- }
- 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) {
- //$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 (!is_null($response) && $halt) {
- 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;
- }
- $this->listeners