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
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 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)); } }
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); }); }); }
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
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', ], ];
de la classe AppProvidersEventServiceProvider
. boot
/** * 注册应用程序中的任何其他事件。 * * @return void */ public function boot() { parent::boot(); Event::listen('event.name', function ($foo, $bar) { // }); }
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 <🎜. >. AppProvidersEventProvider
IlluminateFoundationSupportProvidersEventServiceProvide
Nous 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
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 : IlluminateFoundationSupportProvidersEventServiceProvide
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); } }
events
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); } }
est utilisé pour créer le wildcards
correspondant à l'événement : makeListener
listener
<🎜 >. Lors de la création de
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)); } }; } }
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
createClassListener
Pour 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
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]; } } }
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
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 Subject
correspondances correspondantes. . observers
listener
Dé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
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
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; }
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!