Maison > développement back-end > tutoriel php > Interprétation du système d'événements Laravel

Interprétation du système d'événements Laravel

不言
Libérer: 2023-04-02 17:00:01
original
2062 Les gens l'ont consulté

Cet article présente principalement l'interprétation du système d'événements Laravel, qui a une certaine valeur de référence. Maintenant, je le partage avec tout le monde. Les amis dans le besoin peuvent se référer au

Système d'événements

Laravel Events fournit. une implémentation simple d'observateur qui peut s'abonner et écouter divers événements qui se produisent dans l'application. Le mécanisme événementiel est un bon moyen de découpler les applications, car un événement peut avoir plusieurs écouteurs indépendants les uns des autres. Le système d'événements dans laravel se compose de deux parties. L'une est le nom de l'événement. Le nom de l'événement peut être une chaîne, telle que event.email, ou une classe d'événement, telle que AppEventsOrderShipped ; l'écouteur d'événementlistener, qui peut être une fermeture ou une classe d'écoute, comme AppListenersSendShipmentNotification.

Nous utilisons toujours l'exemple donné dans la documentation officielle pour analyser l'implémentation du code source du système d'événements. Cependant, avant que l'application n'enregistre les événements et les auditeurs, Laravel enregistrera d'abord le traitement des événements au démarrage de l'applicationServices. events

Service d'événement d'inscription Laravel

Parmi les services de base enregistrés lors de la création de l'application Laravel, il existe un

service 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));
    }
}
Copier après la connexion
parmi lequel

est EventServiceProvider /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);
        });
    });
}
Copier après la connexion

est la véritable classe d'implémentation du service IlluminateEventsDispatcher, tandis que la façade events est le proxy statique du service Event, et des méthodes liées au système d'événements sont fournies par events . IlluminateEventsDispatcher

Enregistrement des événements et écoute dans l'application

Nous utilisons toujours l'exemple donné dans la documentation officielle pour analyser l'implémentation du code source du système d'événements. Il existe deux manières d'enregistrer des événements et des auditeurs,

Il existe un tableau AppProvidersEventServiceProvider contenant tous les événements (clés) et les écouteurs (valeurs) correspondant aux événements pour enregistrer tous les écouteurs d'événements, et vous pouvez ajouter des événements de manière flexible en fonction de vos besoins. listen

/**
 * 应用程序的事件监听器映射。
 *
 * @var array
 */
protected $listen = [
    'App\Events\OrderShipped' => [
        'App\Listeners\SendShipmentNotification',
    ],
];
Copier après la connexion
Vous pouvez également enregistrer des fermetures basées sur des événements dans la méthode

de la classe AppProvidersEventServiceProvider. boot

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

    Event::listen('event.name', function ($foo, $bar) {
        //
    });
}
Copier après la connexion
Vous pouvez voir que la tâche principale de la classe

est d'enregistrer les événements dans l'application. La fonction principale de cette classe d'enregistrement est de démarrer le système d'événements. Cette classe hérite de <🎜. >. AppProvidersEventProviderIlluminateFoundationSupportProvidersEventServiceProvideNous avons dit lorsque nous avons ajouté le fournisseur de services qu'après avoir enregistré tous les services, l'application Laravel démarrera ces services en

appelant les méthodes

de tous les fournisseurs, donc les événements dans l'application Laravel et The l'enregistrement de l'auditeur s'effectue dans la méthode IlluminateFoundationBootstrapBootProviders de la classe boot. Jetons un coup d'œil : IlluminateFoundationSupportProvidersEventServiceProvideboot

Vous pouvez voir que le système d'événements est démarré via les méthodes d'écoute et d'abonnement de la
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);
    }
}
Copier après la connexion
. 🎜> service. Pour créer des événements et les auditeurs correspondants ainsi que les abonnés aux événements dans le système.

events

Les noms d'événements contenant des caractères génériques seront uniformément placés dans le tableau
namespace Illuminate\Events;
class Dispatcher implements DispatcherContract
{
    public function listen($events, $listener)
    {
        foreach ((array) $events as $event) {
            if (Str::contains($event, &#39;*&#39;)) {
                $this->setupWildcardListen($event, $listener);
            } else {
                $this->listeners[$event][] = $this->makeListener($listener);
            }
        }
    }
    
    protected function setupWildcardListen($event, $listener)
    {
        $this->wildcards[$event][] = $this->makeListener($listener, true);
    }
}
Copier après la connexion
.

est utilisé pour créer le wildcards correspondant à l'événement : makeListenerlistener<🎜 >. Lors de la création de

, il sera jugé si l'objet d'écoute est une classe d'écoute ou une fonction de fermeture.
class Dispatcher implements DispatcherContract
{
    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));
            }
        };
    }
}
Copier après la connexion

Pour l'écoute de fermeture, listener encapsulera une autre couche et renverra une fonction de fermeture en tant qu'écouteur d'événement.

Pour la classe d'écoute, l'auditeur continuera à être créé via makeListener

createClassListenerPour que la classe d'écoute crée un auditeur à travers la chaîne, elle renverra également une fermeture. Si Si la classe d'écoute actuelle doit exécuter une tâche de file d'attente, la fermeture renvoyée poussera la tâche vers la file d'attente après l'exécution. S'il s'agit d'une classe d'écoute normale, la fermeture renvoyée créera l'objet d'écoute et exécutera la méthode

de l'objet. . Par conséquent, l'écouteur renvoie la fermeture afin d'envelopper le contexte lorsque l'événement est enregistré et appelle la fermeture pour effectuer la tâche en attendant que l'événement soit déclenché.
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, $payload);
            } else {
                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);
        } else {
            return [$this->container->make($class), $method];
        }
    }
}
Copier après la connexion

Après avoir créé l'écouteur, il sera placé dans le tableau avec le nom d'événement correspondant comme clé dans le tableau handle. Il peut y avoir plusieurs tableaux correspondant à un nom d'événement dans le tableau

. 🎜>, tout comme le tableau

dans la classe listener lorsque nous avons déjà parlé du modèle d'observateur, mais Laravel est plus compliqué que cela. Son tableau listener enregistrera plusieurs listener et Subjectcorrespondances correspondantes. . observerslistenerDéclencher l'événementSubject观察者Vous pouvez utiliser le nom de l'événement ou la classe d'événement pour déclencher l'événement. Lors du déclenchement de l'événement, utilisez

, qui provient également du

service

.

Event::fire(new OrdershipmentNotification)Une fois l'événement déclenché, toutes les events fermetures correspondant au nom de l'événement seront trouvées à partir du

généré par l'événement précédemment enregistré, puis ces fermetures seront appelées pour effectuer des tâches dans l'écouteur . Notez que :
public function fire($event, $payload = [], $halt = false)
{
    return $this->dispatch($event, $payload, $halt);
}

public function dispatch($event, $payload = [], $halt = false)
{
    //如果参数$event事件对象,那么就将对象的类名作为事件名称,对象本身作为携带数据的荷载通过`listener`方法
    //的$payload参数的实参传递给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);

        //如果触发事件时传递了halt参数,并且listener返回了值,那么就不会再去调用事件剩下的listener
        //否则就将返回值加入到返回值列表中,等所有listener执行完了一并返回
        if ($halt && ! is_null($response)) {
            return $response;
        }
        //如果一个listener返回了false, 那么将不会再调用事件剩下的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($event)];
    }

    return [$event, Arr::wrap($payload)];
}

//获取事件名对应的所有listener
public 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;
}
Copier après la connexion
  • Si le paramètre de nom d'événement est un objet d'événement, alors le nom de classe de l'objet d'événement sera utilisé comme nom d'événement et lui-même sera transmis à l'écouteur en tant que paramètre de temps.

  • Si le paramètre halt est passé lorsque l'événement est déclenché, après le retour de l'auditeur non-false, l'événement ne continuera pas à être propagé aux auditeurs restants, sinon le retour les valeurs de tous les écouteurs seront Il sera renvoyé uniformément sous forme de tableau une fois tous les écouteurs exécutés.

  • Si un auditeur renvoie une valeur booléenne false alors l'événement cessera immédiatement de se propager aux auditeurs restants.

Le principe du système d'événements de Laravel est toujours le même que le modèle d'observateur mentionné précédemment, mais l'auteur du framework est très compétent et utilise intelligemment les fermetures pour implémenter également le système d'événements. en ce qui concerne les événements nécessitant un traitement en file d'attente, les événements d'application peuvent utiliser le principe de concentration dispersée pour découpler efficacement la logique du code dans l'application dans certains scénarios commerciaux plus complexes. Bien sûr, les événements d'application ne conviennent pas à l'écriture de code dans toutes les circonstances que j'ai écrites. avant d'avoir écrit un article sur la programmation événementielle pour expliquer les scénarios d'application des événements. Si vous êtes intéressé, vous pouvez le lire.

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

Système d'authentification des utilisateurs Laravel (introduction de base)

Laravel 5.5 et supérieur env multi-environnement. configuration lire

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal