この記事では主にLaravelのイベントシステムの解釈を紹介しますが、これは参考になると思いますので、皆さんにもシェアしておきますので、困っている方は参考にしてください
Laravelのイベントが提供するものアプリケーション内で発生するさまざまなイベントをサブスクライブしてリッスンできる単純なオブザーバーの実装。イベントには互いに独立した複数のリスナーを含めることができるため、イベント メカニズムはアプリケーションを分離する良い方法です。 laravel
のイベント システムは 2 つの部分で構成されています。1 つはイベントの名前です。イベントの名前は、event.email
などの文字列にすることも、次のような文字列にすることもできます。 App\Events\OrderShipped
などのイベント クラス; もう 1 つはイベント リスナー listener
で、クロージャまたはリスニング クラス (App\Listeners など) にすることができます。 \Send ShippingNotification
。
イベント システムのソース コード実装を分析するために、引き続き公式ドキュメントに記載されている例を使用しますが、アプリケーションがイベントとリスナーを登録する前に、Laravel はアプリケーションの起動時に最初にイベント処理を登録します。 ##イベントサービス。
Eventservice
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)); } }
EventServiceProvider#があります。 ## は /Illuminate/Events/EventServiceProvider
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">public function register()
{
$this->app->singleton(&#39;events&#39;, function ($app) {
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make(QueueFactoryContract::class);
});
});
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
は events
サービスの実際の実装クラスであり、Event
ファサードは events
サービスの静的プロキシであり、イベント システム関連のメソッドは Illuminate\Events\Dispatcher
によって提供されます。 アプリケーションでのイベントの登録と監視
すべてのイベント リスナーを登録するために、すべてのイベント (キー) とイベントに対応するリスナー (値) を含む listen
配列があり、次に従って柔軟に構成できます。イベントを追加します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">/**
* 应用程序的事件监听器映射。
*
* @var array
*/
protected $listen = [
&#39;App\Events\OrderShipped&#39; => [
&#39;App\Listeners\SendShipmentNotification&#39;,
],
];</pre><div class="contentsignin">ログイン後にコピー</div></div>
イベントベースのクロージャを
クラスの boot
メソッドに登録することもできます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">/**
* 注册应用程序中的任何其他事件。
*
* @return void
*/
public function boot()
{
parent::boot();
Event::listen(&#39;event.name&#39;, function ($foo, $bar) {
//
});
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
クラスの主なジョブは、アプリケーションにイベントを登録することです。この登録クラスの主な機能は、イベント システムを開始することです。このクラスは \Illuminate\Foundation\Support\Providers\EventServiceProvide
を継承します。 サービスプロバイダーを追加したときに、すべてのサービスを登録した後、Laravel アプリケーションは
を通じてすべてのプロバイダーの ブートを呼び出すと述べました
これらのサービスを開始するメソッド。これにより、Laravel アプリケーションでのイベントとリスナーの登録は、\Illuminate\Foundation\Support\Providers\EventServiceProvide
クラスの boot
メソッドで行われます。見てください: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">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);
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
イベント システムは、
サービスのリスニング メソッドとサブスクリプション メソッドを通じて開始され、システム内にイベント、対応するリスナー、およびイベント サブスクライバーを作成することがわかります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">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);
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
ワイルドカードを含むイベント名は、
配列に均一に配置されます。makeListener
は、イベントに対応する listener
を作成するために使用されます。 :<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">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));
}
};
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
を作成する際に、リスニングオブジェクトがリスニングクラスであるかクロージャ関数であるかを判定します。 クロージャ リスニングの場合、
は別のレイヤーをラップし、イベント リスナーとしてクロージャ関数を返します。 リスニング クラスの場合、リスナーは
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">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];
}
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div> を通じて引き続き作成されます。リスニング クラスの文字列を通じてリスナーを作成する場合は、クロージャも返されます。 , 現在のリスニング クラスがキュー タスクを実行する場合、返されたクロージャは実行後にタスクをキューにプッシュします。通常のリスニング クラスの場合、返されたクロージャはリスニング オブジェクトを作成し、オブジェクトのハンドル
メソッド。したがって、リスナーはイベントが登録されるときにコンテキストをラップするためにクロージャを返し、イベントがトリガーされるのを待つときにクロージャを呼び出してタスクを実行します。
リスナーが作成されると、対応するイベント名をキーとして listener
配列に配置されます。配列はに対応します。前にオブザーバーパターンについて説明したときの
クラスの observers
配列と同じように、配列内に複数の listener
を含めることができますが、Laravelはそれよりも複雑です。その listener
配列は、複数の Subject
と対応する Observer
の間の対応する関係を記録します。 イベントのトリガー
イベント名またはイベント クラスを使用してイベントをトリガーできます。イベントをトリガーするときは、
Event::fire(new OrdershipmentNotification)
を使用します。
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; }
からも来ます。イベントがトリガーされると、イベント名に対応するすべての listener
クロージャーが listeners
から見つかります。以前に登録されたイベントによって生成されます。これらのクロージャは、リスナーでタスクを実行するために呼び出されます。注意する必要があるのは:
イベント名パラメータがイベント オブジェクトの場合、イベント オブジェクトのクラス名がイベント名として使用され、それ自体が時間パラメータとしてリスナーに渡されます。
イベントのトリガー時に halt パラメーターが渡された場合、リスナーが非 false
を返した後、イベントは残りのリスナーに伝播し続けません。それ以外の場合は、すべてのリスナーが実行された後、リスナーの戻り値が一律に配列として返されます。
リスナーがブール値 false
を返した場合、イベントは残りのリスナーへの伝播を直ちに停止します。
Laravel のイベント システムの原理は、前述のオブザーバー パターンと同じですが、フレームワークの作成者は非常に熟練しており、クロージャを巧みに組み合わせて適用してイベント システムを実装しています。キュー処理を必要とするイベントの場合と同様に、アプリケーション イベントは、関心の分散の原則を使用して、より複雑なビジネス シナリオでアプリケーション内のコード ロジックを効果的に分離できます。もちろん、アプリケーション イベントは、すべての状況でコードを記述するのに適しているわけではありません。以前、イベント駆動プログラミングに関するイベントの適用シナリオを説明する記事を書きましたので、興味があれば読んでください。
上記がこの記事の全内容です。皆様の学習に少しでもお役に立てれば幸いです。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。
関連推奨事項:
以上がLaravelイベントシステムの解釈の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。