Laravelイベントシステムの解釈

不言
リリース: 2023-04-02 17:00:01
オリジナル
1976 人が閲覧しました

この記事では主にLaravelのイベントシステムの解釈を紹介しますが、これは参考になると思いますので、皆さんにもシェアしておきますので、困っている方は参考にしてください

イベントシステム

Laravelのイベントが提供するものアプリケーション内で発生するさまざまなイベントをサブスクライブしてリッスンできる単純なオブザーバーの実装。イベントには互いに独立した複数のリスナーを含めることができるため、イベント メカニズムはアプリケーションを分離する良い方法です。 laravel のイベント システムは 2 つの部分で構成されています。1 つはイベントの名前です。イベントの名前は、event.email などの文字列にすることも、次のような文字列にすることもできます。 App\Events\OrderShipped などのイベント クラス; もう 1 つはイベント リスナー listener で、クロージャまたはリスニング クラス (App\Listeners など) にすることができます。 \Send ShippingNotification

イベント システムのソース コード実装を分析するために、引き続き公式ドキュメントに記載されている例を使用しますが、アプリケーションがイベントとリスナーを登録する前に、Laravel はアプリケーションの起動時に最初にイベント処理を登録します。 ##イベントサービス。

Laravel登録イベントサービス

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-&gt;app-&gt;singleton(&amp;#39;events&amp;#39;, function ($app) { return (new Dispatcher($app))-&gt;setQueueResolver(function () use ($app) { return $app-&gt;make(QueueFactoryContract::class); }); }); }</pre><div class="contentsignin">ログイン後にコピー</div></div>

Illuminate\Events\Dispatcher

events サービスの実際の実装クラスであり、Event ファサードは events サービスの静的プロキシであり、イベント システム関連のメソッドは Illuminate\Events\Dispatcher によって提供されます。 アプリケーションでのイベントの登録と監視

イベント システムのソース コード実装を分析するために、公式ドキュメントに記載されている例を引き続き使用しています。イベントとリスナーを登録するには 2 つの方法があります。

App\Providers\EventServiceProvider

すべてのイベント リスナーを登録するために、すべてのイベント (キー) とイベントに対応するリスナー (値) を含む listen 配列があり、次に従って柔軟に構成できます。イベントを追加します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">/** * 应用程序的事件监听器映射。 * * @var array */ protected $listen = [ &amp;#39;App\Events\OrderShipped&amp;#39; =&gt; [ &amp;#39;App\Listeners\SendShipmentNotification&amp;#39;, ], ];</pre><div class="contentsignin">ログイン後にコピー</div></div>イベントベースのクロージャを

App\Providers\EventServiceProvider

クラスの 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(&amp;#39;event.name&amp;#39;, function ($foo, $bar) { // }); }</pre><div class="contentsignin">ログイン後にコピー</div></div>

\App\Providers\EventProvider

クラスの主なジョブは、アプリケーションにイベントを登録することです。この登録クラスの主な機能は、イベント システムを開始することです。このクラスは \Illuminate\Foundation\Support\Providers\EventServiceProvide を継承します。 サービスプロバイダーを追加したときに、すべてのサービスを登録した後、Laravel アプリケーションは

\Illuminate\Foundation\Bootstrap\BootProviders

を通じてすべてのプロバイダーの ブートを呼び出すと述べました これらのサービスを開始するメソッド。これにより、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-&gt;listens() as $event =&gt; $listeners) { foreach ($listeners as $listener) { Event::listen($event, $listener); } } foreach ($this-&gt;subscribe as $subscriber) { Event::subscribe($subscriber); } }</pre><div class="contentsignin">ログイン後にコピー</div></div> イベント システムは、

events

サービスのリスニング メソッドとサブスクリプション メソッドを通じて開始され、システム内にイベント、対応するリスナー、およびイベント サブスクライバーを作成することがわかります。 <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, &amp;#39;*&amp;#39;)) { $this-&gt;setupWildcardListen($event, $listener); } else { $this-&gt;listeners[$event][] = $this-&gt;makeListener($listener); } } } protected function setupWildcardListen($event, $listener) { $this-&gt;wildcards[$event][] = $this-&gt;makeListener($listener, true); } }</pre><div class="contentsignin">ログイン後にコピー</div></div>ワイルドカードを含むイベント名は、

wildcards

配列に均一に配置されます。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-&gt;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>

listener

を作成する際に、リスニングオブジェクトがリスニングクラスであるかクロージャ関数であるかを判定します。 クロージャ リスニングの場合、

makeListener

は別のレイヤーをラップし、イベント リスナーとしてクロージャ関数を返します。 リスニング クラスの場合、リスナーは

createClassListener

<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-&gt;createClassCallable($listener), $event, $payload); } else { return call_user_func_array( $this-&gt;createClassCallable($listener), $payload ); } }; } protected function createClassCallable($listener) { list($class, $method) = $this-&gt;parseClassCallable($listener); if ($this-&gt;handlerShouldBeQueued($class)) { //如果当前监听类是队列的话,会将任务推送给队列 return $this-&gt;createQueuedHandlerCallable($class, $method); } else { return [$this-&gt;container-&gt;make($class), $method]; } } }</pre><div class="contentsignin">ログイン後にコピー</div></div> を通じて引き続き作成されます。リスニング クラスの文字列を通じてリスナーを作成する場合は、クロージャも返されます。 , 現在のリスニング クラスがキュー タスクを実行する場合、返されたクロージャは実行後にタスクをキューにプッシュします。通常のリスニング クラスの場合、返されたクロージャはリスニング オブジェクトを作成し、オブジェクトのハンドルメソッド。したがって、リスナーはイベントが登録されるときにコンテキストをラップするためにクロージャを返し、イベントがトリガーされるのを待つときにクロージャを呼び出してタスクを実行します。

リスナーが作成されると、対応するイベント名をキーとして listener 配列に配置されます。配列はに対応します。前にオブザーバーパターンについて説明したときの

Subject

クラスの observers 配列と同じように、配列内に複数の listener を含めることができますが、Laravelはそれよりも複雑です。その listener 配列は、複数の Subject と対応する Observer の間の対応する関係を記録します。 イベントのトリガーイベント名またはイベント クラスを使用してイベントをトリガーできます。イベントをトリガーするときは、Event::fire(new OrdershipmentNotification) を使用します。

events

Service

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 ユーザー認証システム (基本入門)

Laravel5.5 以降のマルチ環境。環境設定の読み取り

以上がLaravelイベントシステムの解釈の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!