Events
registered
- How does the framework load registered events at startup?
- How does the framework trigger events?
1. Register in the container firstevents
Global object of.
The events code is registered in the Application constructor
protected function registerBaseServiceProviders()
{
$this->register(new EventServiceProvider($this));
$this->register(new LogServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
}
Copy the code
A $this – > register (new EventServiceProvider ($this));
$this-> Register () = $this-> Register () = $this-> Register () = $this-> Register (
class EventServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton('events'.function ($app) {
return (new Dispatcher($app)) - >setQueueResolver(function () use ($app) {
return $app->make(QueueFactoryContract::class); }); }); }}Copy the code
2. Register user-defined events
This section covers the Provider startup process, which we covered in Chapter 8, and we’ll jump right to how to start EventServiceProvider.
App. Providers configures the service provider to load.
'providers'=> [ ... App\Providers\EventServiceProvider::class, ... ] .Copy the code
App \ will \ EventServiceProvider: : class boot here () method is framework load when the service provider’s call.
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
public function boot() { parent::boot(); }}Copy the code
Start by starting the parent’s boot() method
class EventServiceProvider extends ServiceProvider
{
protected $listen = [];
protected $subscribe = [];
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 register()
{
//
}
public function listens()
{
return $this->listen; }}Copy the code
The above code is the core of our registration, first through the $listen object
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
Copy the code
This code is the heart of the binding event
Event::listen($event.$listener);
Copy the code
So what does the Event facade return
class Event extends Facade
{
...
protected static function getFacadeAccessor()
{
return 'events'; }}Copy the code
In fact, we’re back where we started, events is the closure that was originally bound
$this->app->singleton('events'.function ($app) {
return (new Dispatcher($app)) - >setQueueResolver(function () use ($app) {
return $app->make(QueueFactoryContract::class);
});
});
Copy the code
Events is the class Illuminate events Dispatcher! Let’s look at the Dispatcher’s Listen method
public function listen($events.$listener)
{
foreach ((array) $events as $event) {
if (Str::contains($event.The '*')) {
$this->setupWildcardListen($event.$listener);
} else {
$this->listeners[$event=] []$this->makeListener($listener); }}}Copy the code
So if it’s a global event it goes to $this->wildcards otherwise it goes to $this-> Listeners.
Continue to look at $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);
}
return $listener(... array_values($payload));
};
}
Copy the code
$notice [$event] is the result of the closure. At this point we have resolved how the framework registers events that are already written.
3. Subscriber registration
In addition to the one-to-one binding, events implement a one-to-many binding that is the subscriber
public function boot() {... foreach ($this->subscribe as $subscriber) {
Event::subscribe($subscriber); }}Copy the code
Go back to the boot() method, execute the normal Event registration, and then start registering subscribe to the Dispatcher object.
public function subscribe($subscriber{/ /Parse the incoming abstraction from the container and return the corresponding instance.
$subscriber = $this->resolveSubscriber($subscriber);
// "The call returns an instance subscribe($this) method at the same time$dispatcherObject"
$subscriber->subscribe($this);
}
Copy the code
So what happens in subscribe($this)?
Here I have listed a demo, written according to the official.
public function subscribe($events)
{
$events->listen(
'App\Events\MyEvents'.'App\Listeners\MySubscribe@funName()'
);
}
Copy the code
Finally, the Listen method is called, but this allows a subscriber to listen for multiple events and optionally trigger the corresponding method based on the event.
fire events !
$dispatcher = $dispatcher = $dispatcher = $dispatcher
The core method of the event invocation.
public function dispatch($event.$payload= [].$halt = false) {[$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 ($halt&&! is_null($response)) {
return $response;
}
if ($response= = =false) {
break;
}
$responses[] = $response;
}
return $halt ? null : $responses;
}
Copy the code
Let’s look at the system’s default event return value
[$event.$payload] = $this->parseEventAndPayload(
$event.$payload
);
Copy the code
This code is the event broadcast trigger
if ($this->shouldBroadcast($payload)) {
$this->broadcastEvent($payload[0]);
}
Copy the code
Starts traversing the listener class that is resolved from the given event
foreach ($this->getListeners($event) as $listener) {... }Copy the code
$listeners ->getListeners($notice); methods
public function getListeners($eventName)
{
$listeners = $this->listeners[$eventName]???? [];$listeners = array_merge(
$listeners.$this->wildcardsCache[$eventName]????$this->getWildcardListeners($eventName));return class_exists($eventName.false)?$this->addInterfaceListeners($eventName.$listeners)
: $listeners;
}
Copy the code
The main logic here is to see if there are bindings in the $this->listeners
Return the corresponding class if it exists, otherwise return the corresponding implementation interface.
$response = $listener($event, $payload);
The $listener here is the closure returned by calling makeListerer() at the time of the above binding.
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));
};
}
Copy the code
The argument passed here, $event, is the object of the event class we wrote
$payload is the parameter you want to pass in to carry.
The closure logic will be explained later.
conclusion
Events provides the benefit of decoupling development, and the framework is used in many places
For example, the observer of the model is based on the event system.