<article><h1>Laravel 的事件系統</h1><ul><li><a href="#introduction">簡介</a></li><li><a href="#registering-events-and-listeners">注冊事件與監聽器</a><ul><li><a href="#generating-events-and-listeners">生成事件與監聽器</a></li><li><a href="#manually-registering-events">手動注冊事件</a></li></ul></li><li><a href="#defining-events">定義事件</a></li><li><a href="#defining-listeners">定義監聽器</a></li><li><a href="#queued-event-listeners">隊列化事件監聽器</a><ul><li><a href="#manually-accessing-the-queue">手動訪問隊列</a></li><li><a href="#handling-failed-jobs">處理失敗任務</a></li></ul></li><li><a href="#dispatching-events">觸發事件</a></li><li><a href="#event-subscribers">事件訂閱者</a><ul><li><a href="#writing-event-subscribers">編寫事件訂閱者</a></li><li><a href="#registering-event-subscribers">注冊事件訂閱者</a></li></ul></li></ul><p><a name="introduction"></a></p><h2><a href="#introduction">簡介</a></h2><p>Laravel 事件機制實現了一個簡單的觀察者模式,讓我們可以訂閱和監聽應用中出現的各種事件。事件類 (Event) 類通常保存在 <code class=" language-php">app<span class="token operator">/</span>Events</code> 目錄下,而它們的監聽類 (Listener) 類被保存在 <code class=" language-php">app<span class="token operator">/</span>Listeners</code> 目錄下。如果你在應用中看不到這些文件夾也不要擔心,因為當你使用 Artisan 命令來生成事件和監聽器時他們會被自動創建。</p><p>事件機制是一種很好的應用解耦方式,因為一個事件可以擁有多個互不依賴的監聽器。例如,每次把用戶的訂單發完貨后都希望給他發個 Slack 通知。這時候你可以發起一個 <code class=" language-php">OrderShipped</code> 事件,它會被監聽器接收到再傳遞給 Slack 通知模塊,這樣你就不用把訂單處理的代碼跟 Slack 通知的代碼耦合在一起了。</p><p><a name="registering-events-and-listeners"></a></p><h2><a href="#registering-events-and-listeners">注冊事件和監聽器</a></h2><p>Laravel 應用中的 <code class=" language-php">EventServiceProvider</code> 提供了一個很方便的地方來注冊所有的事件監聽器。它的 <code class=" language-php">listen</code> 屬性是一個數組,包含所有的事件(鍵)以及事件對應的監聽器(值)。你也可以根據應用需求來增加事件到這個數組中。例如,增加一個 <code class=" language-php">OrderShipped</code> 事件:</p><pre class=" language-php"><code class=" language-php"><span class="token comment" spellcheck="true">/**
* 應用程序的事件監聽器映射。
*
* @var array
*/</span>
<span class="token keyword">protected</span> <span class="token variable">$listen</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token string">'App\Events\OrderShipped'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\SendShipmentNotification'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre><p><a name="generating-events-and-listeners"></a></p><h3>生成事件和監聽器</h3><p>當然,手動創建每個事件和監聽器是很麻煩的。簡單的方式是,在 <code class=" language-php">EventServiceProvider</code> 類中添加好事件和監聽器,然后使用 <code class=" language-php">event<span class="token punctuation">:</span>generate</code> 命令。這個命令會自動生成 <code class=" language-php">EventServiceProvider</code> 類中列出的所有事件和監聽器。當然已經存在的事件和監聽器將保持不變:</p><pre class=" language-php"><code class=" language-php">php artisan event<span class="token punctuation">:</span>generate</code></pre><p><a name="manually-registering-events"></a></p><h3>手動注冊事件</h3><p>一般來說,事件必須通過 <code class=" language-php">EventServiceProvider</code> 類的 <code class=" language-php"><span class="token variable">$listen</span></code> 數組進行注冊;不過,你也可以在 <code class=" language-php">EventServiceProvider</code> 類的 <code class=" language-php">boot</code> 方法中注冊閉包事件。</p><pre class=" language-php"><code class=" language-php"><span class="token comment" spellcheck="true">/**
* 注冊應用程序中的任何其他事件。
*
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">boot<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token scope"><span class="token keyword">parent</span><span class="token punctuation">::</span></span><span class="token function">boot<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Event<span class="token punctuation">::</span></span><span class="token function">listen<span class="token punctuation">(</span></span><span class="token string">'event.name'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$foo</span><span class="token punctuation">,</span> <span class="token variable">$bar</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><h4>通配符事件監聽器</h4><p>你甚至可以在注冊監聽器時使用 <code class=" language-php"><span class="token operator">*</span></code> 通配符參數,它讓你在一個監聽器中可以監聽到多個事件。通配符監聽器接受的第一個參數是事件名稱,第二個參數是整個的事件數據:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Event<span class="token punctuation">::</span></span><span class="token function">listen<span class="token punctuation">(</span></span><span class="token string">'event.*'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$eventName</span><span class="token punctuation">,</span> <span class="token keyword">array</span> <span class="token variable">$data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="defining-events"></a></p><h2><a href="#defining-events">定義事件</a></h2><p>事件類就是一個包含與事件相關信息數據的容器。例如,假設我們生成的 <code class=" language-php">OrderShipped</code> 事件接受一個 <a href="/docs/5.4/eloquent">Eloquent ORM</a> 對象:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Events</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Order</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>SerializesModels</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">OrderShipped</span>
<span class="token punctuation">{</span>
<span class="token keyword">use</span> <span class="token package">SerializesModels</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token variable">$order</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">/**
* 創建一個事件實例。
*
* @param Order $order
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct<span class="token punctuation">(</span></span>Order <span class="token variable">$order</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">order</span> <span class="token operator">=</span> <span class="token variable">$order</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>正如你所見,這個事件類中沒有包含其它邏輯。它僅只是一個被構建的 <code class=" language-php">Order</code> 對象的容器。如果使用 PHP 的 <code class=" language-php">serialize</code> 函數對事件進行序列化,使用了 <code class=" language-php">SerializesModels</code> trait 的事件將會優雅的序列化任何的 Eloquent 模型。</p><p><a name="defining-listeners"></a></p><h2><a href="#defining-listeners">定義監聽器</a></h2><p>接下來,讓我們看一下例子中事件的監聽器。事件監聽器在 <code class=" language-php">handle</code> 方法中接受了事件實例作為參數。 <code class=" language-php">event<span class="token punctuation">:</span>generate</code> 命令將會在事件的 <code class=" language-php">handle</code> 方法中自動加載正確的事件類和類型提示。在 <code class=" language-php">handle</code> 方法中,你可以運行任何需要響應該事件的業務邏輯。</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>OrderShipped</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">SendShipmentNotification</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 創建事件監聽器。
*
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span> <span class="token punctuation">}</span>
<span class="token comment" spellcheck="true">/**
* 處理事件
*
* @param OrderShipped $event
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">handle<span class="token punctuation">(</span></span>OrderShipped <span class="token variable">$event</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // 使用 $event->order 來訪問 order ...
</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> 你的事件監聽器也可以在構造函數中對任何依賴使用類型提示。所有的事件監聽器會經由 Laravel 的 <a href="/docs/5.4/container">服務容器</a> 做解析,所以所有的依賴都將會被自動注入:</p></blockquote><h4>停止事件傳播</h4><p>有時,你可能希望停止一個事件傳播到其他的監聽器。這時你可以通過在監聽器的 <code class=" language-php">handle</code> 方法中返回 <code class=" language-php"><span class="token boolean">false</span></code> 來實現。</p><p><a name="queued-event-listeners"></a></p><h2><a href="#queued-event-listeners">隊列化事件監聽器</a></h2><p>如果你的監聽器中需要實現一些耗時的任務,比如發送郵件或者進行 HTTP 請求,那把它放到隊列中處理是非常有用的。在使用隊列化監聽器之前,一定要在服務器或者本地環境中配置 <a href="/docs/5.4/queues">隊列</a> 并開啟一個隊列監聽器。</p><p>要對監聽器進行隊列化的話,只需增加 <code class=" language-php">ShouldQueue</code> 接口到你的監聽器類。由 Artisan 命令 <code class=" language-php">event<span class="token punctuation">:</span>generate</code> 生成的監聽器已經將此接口導入到命名空間了,因此你可以直接使用它:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>OrderShipped</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">SendShipmentNotification</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span><span class="token punctuation">}</span></code></pre><p>就這樣!當事件被監聽器調用時, 事件分發器會使用 Laravel 的 <a href="/docs/5.4/queues">隊列系統</a> 自動將它進行隊列化。如果監聽器通過隊列運行且沒有拋出任何異常,則已執行完的任務將會自動從隊列中刪除。</p><h4>自定義隊列的連接和名稱</h4><p>如果你想要自定義隊列的連接和名稱,你可以在監聽器類中定義 <code class=" language-php"><span class="token variable">$connection</span></code> 和 <code class=" language-php"><span class="token variable">$queue</span></code> 屬性。</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>OrderShipped</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">SendShipmentNotification</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 隊列化任務使用的連接名稱。
*
* @var string|null
*/</span>
<span class="token keyword">public</span> <span class="token variable">$connection</span> <span class="token operator">=</span> <span class="token string">'sqs'</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">/**
* 隊列化任務使用的隊列名稱。
*
* @var string|null
*/</span>
<span class="token keyword">public</span> <span class="token variable">$queue</span> <span class="token operator">=</span> <span class="token string">'listeners'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><p><a name="manually-accessing-the-queue"></a></p><h3>手動訪問隊列</h3><p>如果你需要手動訪問底層隊列任務的 <code class=" language-php">delete</code> 和 <code class=" language-php">release</code> 方法,你可以使用 <code class=" language-php">Illuminate\<span class="token package">Queue<span class="token punctuation">\</span>InteractsWithQueue</span></code> trait 來實現。這個 trait 在生成的監聽器中是默認加載的,它提供了這些方法:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>OrderShipped</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>InteractsWithQueue</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">SendShipmentNotification</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span>
<span class="token punctuation">{</span>
<span class="token keyword">use</span> <span class="token package">InteractsWithQueue</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">handle<span class="token punctuation">(</span></span>OrderShipped <span class="token variable">$event</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">release<span class="token punctuation">(</span></span><span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p><a name="handling-failed-jobs"></a></p><h3>處理失敗任務</h3><p>有時你隊列化的事件監聽器可能失敗了。如果隊列監聽器任務執行次數超過在工作隊列中定義的最大嘗試次數,監聽器的 <code class=" language-php">failed</code> 方法將會被自動調用。 <code class=" language-php">failed</code> 方法接受事件實例和失敗的異常作為參數:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>OrderShipped</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>InteractsWithQueue</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">SendShipmentNotification</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span>
<span class="token punctuation">{</span>
<span class="token keyword">use</span> <span class="token package">InteractsWithQueue</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">handle<span class="token punctuation">(</span></span>OrderShipped <span class="token variable">$event</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">failed<span class="token punctuation">(</span></span>OrderShipped <span class="token variable">$event</span><span class="token punctuation">,</span> <span class="token variable">$exception</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p><a name="dispatching-events"></a></p><h2><a href="#dispatching-events">觸發事件</a></h2><p>如果要觸發事件,你可以傳遞一個事件實例給 <code class=" language-php">event</code> 輔助函數。這個函數將會把事件分發到它所有已經注冊的監聽器上。因為 <code class=" language-php">event</code> 函數是全局可訪問的,所以你可以在應用中的任何地方調用它:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Order</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>OrderShipped</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">OrderController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 將傳遞過來的訂單發貨。
*
* @param int $orderId
* @return Response
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">ship<span class="token punctuation">(</span></span><span class="token variable">$orderId</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token variable">$order</span> <span class="token operator">=</span> <span class="token scope">Order<span class="token punctuation">::</span></span><span class="token function">findOrFail<span class="token punctuation">(</span></span><span class="token variable">$orderId</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true"> // 訂單的發貨邏輯...
</span>
<span class="token function">event<span class="token punctuation">(</span></span><span class="token keyword">new</span> <span class="token class-name">OrderShipped</span><span class="token punctuation">(</span><span class="token variable">$order</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> 測試時,不用真的觸發監聽器就能斷言事件類型是很有用的。 Laravel <a href="/docs/5.4/mocking#mocking-events">內置的測試輔助方法</a> 能讓這件事變得很容易。</p></blockquote><p><a name="event-subscribers"></a></p><h2><a href="#event-subscribers">事件訂閱者</a></h2><p><a name="writing-event-subscribers"></a></p><h3>編寫事件訂閱者</h3><p>事件訂閱者是一個在自身內部可以訂閱多個事件的類,允許你在單個類中定義多個事件處理器。訂閱者應該定義一個 <code class=" language-php">subscribe</code> 方法,這個方法接受一個事件分發器的實例。你可以調用事件分發器的 <code class=" language-php">listen</code> 方法來注冊事件監聽器:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Listeners</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">UserEventSubscriber</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 處理用戶登錄事件。
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">onUserLogin<span class="token punctuation">(</span></span><span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token comment" spellcheck="true">/**
* 處理用戶注銷事件。
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">onUserLogout<span class="token punctuation">(</span></span><span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token comment" spellcheck="true">/**
* 為訂閱者注冊監聽器。
*
* @param Illuminate\Events\Dispatcher $events
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">subscribe<span class="token punctuation">(</span></span><span class="token variable">$events</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token variable">$events</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">listen<span class="token punctuation">(</span></span>
<span class="token string">'Illuminate\Auth\Events\Login'</span><span class="token punctuation">,</span>
<span class="token string">'App\Listeners\UserEventSubscriber@onUserLogin'</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$events</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">listen<span class="token punctuation">(</span></span>
<span class="token string">'Illuminate\Auth\Events\Logout'</span><span class="token punctuation">,</span>
<span class="token string">'App\Listeners\UserEventSubscriber@onUserLogout'</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p><a name="registering-event-subscribers"></a></p><h3>注冊事件訂閱者</h3><p>一旦訂閱者被定義,它就可以被注冊到事件分發器中。你可以在 <code class=" language-php">EventServiceProvider</code> 類的 <code class=" language-php"><span class="token variable">$subscribe</span></code> 屬性注冊訂閱者。例如,添加 <code class=" language-php">UserEventSubscriber</code> 到列表中:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Providers<span class="token punctuation">\</span>EventServiceProvider</span> <span class="token keyword">as</span> ServiceProvider<span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">EventServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 應用中事件監聽器的映射。
*
* @var array
*/</span>
<span class="token keyword">protected</span> <span class="token variable">$listen</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token comment" spellcheck="true"> //
</span> <span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">/**
* 需要注冊的訂閱者類。
*
* @var array
*/</span>
<span class="token keyword">protected</span> <span class="token variable">$subscribe</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token string">'App\Listeners\UserEventSubscriber'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre></article>
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 請求周期
- 開發環境部署
- Valet
- Homestead
- 核心概念
- 服務提供者
- Facades
- Contracts
- 服務容器
- HTTP 層
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- Session
- 表單驗證
- 前端
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- API 認證
- 用戶認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- Redis
- 數據填充
- Eloquent ORM
- Eloquent ORM快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- 序列化
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 錯誤與日志
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度