Interpretation of Laravel Event System

Source: Internet
Author: User
This article mainly introduces the interpretation of the Laravel event System, has a certain reference value, now share to everyone, the need for friends can refer to

Event System

The Laravel event provides a simple observer implementation that subscribes to and listens to various events that occur in the application. The event mechanism is a good way to apply decoupling because an event can have multiple listeners that are not dependent on each other. laravelThe event system consists of two parts, one is the name of the event, the name of the event can be a string, for example event.email , it can be an event class, for example, the App\Events\OrderShipped other is the listener of the event, listener can be a closure, or it can be a listener class, for example App\Listeners\SendShipmentNotification .

We still use this example from the official documentation to analyze the source implementation of the event system down, but before registering the event and listener, Laravel registers the service that handles the event before the app starts events .

Laravel Registering the Event Service

Laravel applications are serviced at the time of the creation of the basic services registered Event

Namespace Illuminate\foundation;class application extends Container implements ... {Public    function __construct ($basePath = null)    {        ...        $this->registerbaseserviceproviders ();        ...    }        protected function Registerbaseserviceproviders ()    {        $this->register (New Eventserviceprovider ($this));        $this->register (New Logserviceprovider ($this));        $this->register (New Routingserviceprovider ($this));}    }

One of them EventServiceProvider is/Illuminate/Events/EventServiceProvider

Public Function Register () {    $this->app->singleton (' Events ', function ($app) {        return (new Dispatcher ( $app))->setqueueresolver (function () use ($app) {            return $app->make (queuefactorycontract::class);        });    });}

Illuminate\Events\Dispatcheris the events real implementation of the service class, and the Event façade when events the service static proxy, event system-related methods are provided by the Illuminate\Events\Dispatcher .

Registering events and listening in apps

We still use this example in the official documentation to analyze the source implementation of the event system down, registering events and listeners in two ways, with an App\Providers\EventServiceProvider listen array containing all the events (keys) and the Listener (value) corresponding to the event to register all event listeners, with the flexibility to add events on demand.

/** * Application Event listener mapping. * * @var array */protected $listen = [    ' app\events\ordershipped ' = = [        ' app\listeners\ Sendshipmentnotification ',    ],];

App\Providers\EventServiceProviderEvent-based closures can also be registered in the methods of the class boot .

/** * Register any other events in the application. * * @return void */public function boot () {    parent::boot ();    Event::listen (' Event.name ', function ($foo, $bar) {        //    });}

You can see that the \App\Providers\EventProvider main function of the class is to register the events in the application, the main role of this registration class is the start of the event system, this class inherits from \Illuminate\Foundation\Support\Providers\EventServiceProvide .

As we said in the service provider, the Laravel application \Illuminate\Foundation\Bootstrap\BootProviders starts these services by calling all provider methods after registering all the services boot , so the registration of events and listeners in the Laravel application takes place in the method of the \Illuminate\Foundation\Support\Providers\EventServiceProvide class boot , let's look at:

Public Function boot () {    foreach ($this->listens () as $event = + $listeners) {        foreach ($listeners as $listen ER) {            event::listen ($event, $listener);        }    }    foreach ($this->subscribe as $subscriber) {        event::subscribe ($subscriber);}    }

You can see that the event system is started by a events service listener and subscription method to create events with corresponding listeners and event subscribers in the system.

Namespace Illuminate\events;class Dispatcher implements dispatchercontract{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)            ;        }} protected function Setupwildcardlisten ($event, $listener)    {        $this->wildcards[$event] = $this Makelistener ($listener, True);}    }

For event names that contain wildcards, they are uniformly placed in the wildcards array and makeListener are used to create events corresponding to listener :

Class Dispatcher implements dispatchercontract{public    function Makelistener ($listener, $wildcard = False)    {        if (is_string ($listener)) {//If the listener is a class, go to create a listener class            return $this->createclasslistener ($listener, $wildcard);        }        return function ($event, $payload) use ($listener, $wildcard) {            if ($wildcard) {                return $listener ($event, $p ayload);            } else {                return $listener (... array_values ($payload));}}        ;}}    

When it is created, it determines whether the listener listener is a listener class or a closure function.

For the closure listener, makeListener a layer is then wrapped to return a closure function as the listener for the event.

For the listener class, the listener will continue to be createClassListener created by

class Dispatcher implements dispatchercontract{public function Createclasslistener ($listener, $wildcard = False) {return function ($event, $payload) use ($listener, $wildcard {if ($wildcard) {return Call_user_func ($this->createclasscallable ($listener), $event, $pa            Yload);                 } else {return Call_user_func_array ($this->createclasscallable ($listener), $payload            );    }        }; } protected function Createclasscallable ($listener) {list ($class, $method) = $this->parseclasscallable ($l        Istener); if ($this->handlershouldbequeued ($class)) {//If the current listener class is a queue, the task is pushed to the queue return $this->createqueue        Dhandlercallable ($class, $method);        } else {return [$this->container->make ($class), $method]; }    }}

For a listener that is created by listening to a string of classes, a closed packet is returned, and if the current listener class is to perform a queue task, the returned closure is pushed to the queue after execution, and if the listener is made out of the closed packet returned by the normal listener class, the object's method is executed handle . So the listener returns the closure in order to wrap the context of the event registration and to wait for the event to be triggered to invoke the closure to perform the task.

After the listener is created, it is placed in an array listener with the corresponding event name as the key, and listener there can be more than one array of event names in the array, listener just like the Subject array in the class before we spoke the Observer pattern observers . But Laravel is more complicated than that, and its listener array will record multiple Subject and corresponding correspondence 观察者 .

Triggering events

Events can be triggered with an event name or event class, and the event is triggered by the Event::fire(new OrdershipmentNotification) same time it comes from the events service

Public function Fire ($event, $payload = [], $halt = False) {return $this->dispatch ($event, $payload, $halt);} Public Function Dispatch ($event, $payload = [], $halt = False) {///if the parameter $event the event object, the object's class name is the event, and the object itself acts as a load carrying data through ' listen    The $payload argument of the ER ' method//is passed to the listener 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 the halt parameter is passed when the event is triggered, and listener returns the value, then no more calls are made to the event listener//or the return value is added to the return value list, and all listener is returned if it is executed ($halt &A mp;&!        Is_null ($response)) {return $response;        }//If a listener returns false, then the event will no longer be called the remaining listener if ($response = = = False) {break;    } $responses [] = $response; } return $halt? Null: $responses;} protected function ParsEeventandpayload ($event, $payload) {if (Is_object ($event)) {list ($payload, $event) = [[$event], Get_class ($even    T)]; } return [$event, Arr::wrap ($payload)];} Gets the event name for all Listenerpublic function Getlisteners ($eventName) {$listeners = Isset ($this->listeners[$eventName])?    this->listeners[$eventName]: [];    $listeners = Array_merge ($listeners, $this->getwildcardlisteners ($eventName)); Return Class_exists ($eventName, false)? $this->addinterfacelisteners ($eventName, $listeners): $listeners;}

After the event is triggered, listeners all closures corresponding to the event name are found in the previous registration event generation, listener and then the closures are called to perform the tasks in the listener, and it is important to note that:

    • If the event name parameter event object, then the event object's class name is used, which itself is passed as a time parameter to listener.

    • If the halt parameter is passed when the event is triggered, the false event will not continue to propagate to the remaining listener after listener returns, otherwise all listener return values will be returned as an array in all listener executions.

    • If a listener returns a Boolean value false then the event stops propagating to the remaining listener immediately.

The Laravel Event System principle is the same as the observer pattern previously spoken, but the author of the framework has a deep, ingenious combination of closures to implement the event system, and for events that require queue processing, Application events in some of the more complex business scenarios can be used to effectively decouple the code logic in the application using the principle of focus dispersion, and certainly not the case can be adapted to the application of events to write code, I have previously written an article event-driven programming to illustrate the application scenario of the event, interested can go to see.

The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.