事件(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事件定義必須在全域事件定義檔中定義,其它事件支援在應用程式的事件定義檔中定義。

原來5.1的一些行為標籤已經廢棄,所有取消的標籤都可以使用中間件更好的替代品。可以把中間件看成處理請求以及回應輸出相關的特殊事件。事實上,中間件的handler方法只是具有特殊的參數以及回傳值而已。

資料庫操作的回呼也稱為查詢事件,是針對資料庫的CURD操作而設計的回呼方法,主要包括:

描述select查詢前回呼find查詢前回呼insert操作成功後回呼update操作成功後回呼delete操作成功後回呼
事件
#before_select
before_find
after_insert
after_update
#after_delete

#查詢事件的參數就是目前的查詢物件實例。

模型事件包含:

查詢後##新增前after_insert新增後before_update更新前after_updatebefore_write
#鉤子
##after_read
#before_insert
##更新後
寫入前


after_write

寫入後

######before_delete#######刪除前#############after_delete######刪除後######### ######################### ###