事件(Event)
如何定義事件?
事件系統的所有操作都透過think\facade\Event類別進行靜態呼叫
事件系統使用了觀察者模式(可參考PHP設計模式),提供了解耦應用的更好方式。
在你需要監聽事件的位置,例如下面我們在使用者完成登入操作之後加入以下事件觸發程式碼:
// 触发UserLogin事件 用于执行用户登录后的一系列操作 Event::trigger('UserLogin');
這裡UserLogin表示一個事件標識,如果你定義了單獨的事件類,你可以使用事件類名(甚至可以傳入一個事件類實例)。
// 直接使用事件类触发 event('app\event\UserLogin');
事件類別可以透過命令列快速產生
php think make:event UserLogin
預設會產生一個app\event\UserLogin事件類,也可以指定完整類別名稱產生。
我們可以為事件類別新增方法
namespace app\event; use app\model\User; class UserLogin { public $user; public function __construct(User $user) { $this->user = $user; } }
一般事件類別無需繼承任何其它類別。
你可以給事件類別綁定一個事件標識,一般建議直接在應用的event.php事件定義檔中批次綁定。
return [ 'bind' => [ 'UserLogin' => 'app\event\UserLogin', // 更多事件绑定 ], ];
如果你需要動態綁定,可以使用
Event::bind(['UserLogin' => 'app\event\UserLogin']);
ThinkPHP的事件系統不依賴事件類,如果沒有額外的需求,僅透過事件標識也可以使用,省去定義事件類的麻煩。
如果你沒有定義事件類別的話,則無需綁定。對於大部分的場景,可能確實不需要定義事件類別。
你可以在event方法中傳入一個事件參數
// user是当前登录用户对象实例 event('UserLogin', $user);
監聽事件
你可以手動註冊一個事件監聽
Event::listen('UserLogin', function($user) { // });
或使用監聽類別來執行監聽
Event::listen('UserLogin', 'app\listener\UserLogin');
可以透過命令列快速產生一個事件監聽類別
php think make:listener UserLogin
預設會產生一個app\listener\UserLogin事件監聽類,也可以指定完整類別名稱產生。
事件監聽類別只需要定義一個handle方法,支援依賴注入。
<?php namespace app\listener; class UserLogin { public function handle($user) { // 事件监听处理 } }
在handle方法中如果傳回了false,則表示監聽中止,將不再執行該事件後面的監聽。
一般建議直接在事件定義檔中定義對應事件的監聽。
return [ 'bind' => [ 'UserLogin' => 'app\event\UserLogin', // 更多事件绑定 ], 'listen' => [ 'UserLogin' => ['app\listener\UserLogin'], // 更多事件监听 ], ];
事件訂閱
可以透過事件訂閱機制,在一個監聽器中監聽多個事件,例如透過命令列產生一個事件訂閱者類,
php think make:subscribe User
預設會產生app\subscribe\User類,或者你可以指定完整類名生成。
然後你可以在事件訂閱類別中新增不同事件的監聽方法,例如。
<?php namespace app\subscribe; class User { public function onUserLogin($user) { // UserLogin事件响应处理 } public function onUserLogout($user) { // UserLogout事件响应处理 } }
監聽事件的方法命名規格是on 事件標識(駝峰命名),然後在事件定義檔註冊事件訂閱者。
return [ 'bind' => [ 'UserLogin' => 'app\event\UserLogin', // 更多事件绑定 ], 'listen' => [ 'UserLogin' => ['app\listener\UserLogin'], // 更多事件监听 ], 'subscribe' => [ 'app\subscribe\User', // 更多事件订阅 ], ];
如果希望統一加入事件前綴標識,可以定義eventPrefix屬性。
<?php namespace app\subscribe; class User { protected $eventPrefix = 'User'; public function onLogin($user) { // UserLogin事件响应处理 } public function onLogout($user) { // UserLogout事件响应处理 } }
如果希望自訂訂閱方式(或方法規範),可以定義subscribe方法實作。
<?php namespace app\subscribe; use think\Event; class User { public function onUserLogin($user) { // UserLogin事件响应处理 } public function onUserLogout($user) { // UserLogout事件响应处理 } public function subscribe(Event $event) { $event->listen('UserLogin', [$this,'onUserLogin']); $event->listen('UserLogout',[$this,'onUserLogout']); } }
如果需要動態註冊,可以使用
Event::subscribe('app\index\subscribe\User');
內建事件
##內建的系統事件包含:
事件 | 描述 | 參數 |
---|---|---|
AppInit | 應用初始化標籤位元 | 無 |
HttpRun | 應用程式開始標籤位元 | |
##HttpEnd | 應用結束標籤位元 | |
LogWrite | 日誌write方法標籤位 | |
LogLevel | #日誌寫入標籤位元 | |
RouteLoaded | 路由載入完成 |
AppInit事件定義必須在全域事件定義檔中定義,其它事件支援在應用程式的事件定義檔中定義。
資料庫操作的回呼也稱為查詢事件,是針對資料庫的CURD操作而設計的回呼方法,主要包括:
事件 | |
---|---|
#before_select
| select|
before_find
| find|
after_insert
| insert|
after_update
| update|
#after_delete
| delete
#查詢事件的參數就是目前的查詢物件實例。
模型事件包含:
#鉤子 | |
---|---|
##after_read | |
#before_insert | ##新增前|
新增後 | |
更新前 | |
##更新後 |
after_write