### 2019 年 4 月 21 日 發布
在最新的`6.0`版本中引入了新的事件系統用以替代`5.1`版本的行為,同時也接管了數據庫事件和模型事件。
本篇主要描述下新版的事件系統以及查詢事件、模型事件的使用。
## 定義事件
>[danger] 事件系統的所有操作都通過`think\facade\Event`類進行靜態調用
事件系統使用了觀察者模式,提供了解耦應用的更好方式。在你需要監聽事件的位置,添加如下代碼:
```
Event::trigger('UserLogin');
```
或者使用助手函數
```
event('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::bind('UserLogin', 'app\event\UserLogin');
```
或者在應用的`event.php`事件定義文件中批量綁定。
```
return [
'bind' => [
'UserLogin' => 'app\event\UserLogin',
// 更多事件綁定
],
];
```
如果你沒有定義事件類的話,則無需綁定。
>[info] ThinkPHP的事件系統不依賴事件類,如果沒有額外的需求,僅通過事件標識也可以使用。
你可以在`event`方法中傳入一個事件參數
```
event('UserLogin', $user);
```
## 事件監聽
你可以手動注冊一個事件監聽
```
Event::listen('UserLogin', function($user) {
//
});
```
或者使用監聽類
```
Event::listen('UserLogin', 'app\listener\UserLogin');
```
可以通過命令行快速生成一個事件監聽類
```
php think make:listener UserLogin
```
默認會生成一個`app\listener\UserLogin`事件監聽類,也可以指定完整類名生成。
事件監聽類只需要定義一個`handler`方法,支持依賴注入。
~~~
<?php
namespace app\listener;
class UserLogin
{
public function handle($user)
{
// 事件監聽處理
}
}
~~~
在`handler`方法中如果返回了`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)
{
// 事件響應處理
}
public function onUserLogout($user)
{
// 事件響應處理
}
}
~~~
監聽事件的方法命名規范是`on`+事件標識(駝峰命名),然后注冊該事件訂閱
```
Event::subscribe('app\subscribe\User');
```
一般建議直接在事件定義文件中定義
```
return [
'bind' => [
'UserLogin' => 'app\event\UserLogin',
// 更多事件綁定
],
'listen' => [
'UserLogin' => ['\app\listener\UserLogin'],
// 更多事件監聽
],
'subscribe' => [
'\app\subscribe\User',
// 更多事件訂閱
],
];
```
## 內置事件
內置的系統事件包括:
| 事件| 描述 | 參數 |
| --- | --- | --- |
| AppInit | 應用初始化標簽位 | 無 |
| HttpRun | 應用開始標簽位 | 無 |
| HttpEnd | 應用結束標簽位 | 當前響應對象實例 |
| LogWrite | 日志write方法標簽位 | 當前寫入的日志信息 |
| LogLevel | 日志寫入標簽位 | 包含日志類型和日志信息的數組 |
>[danger] `AppInit`事件定義必須在全局事件定義文件中定義,其它事件支持在應用的事件定義文件中定義。
原來`5.1`的一些行為標簽已經廢棄,所有取消的標簽都可以使用中間件更好的替代。可以把中間件看成處理請求以及響應輸出相關的特殊事件。事實上,中間件的`handle`方法只是具有特殊的參數以及返回值而已。
## 查詢事件
數據庫操作的回調也稱為查詢事件,是針對數據庫的CURD操作而設計的回調方法,主要包括:
| 事件 | 描述 |
| --- | --- |
| before\_select | `select`查詢前回調 |
| before\_find | `find`查詢前回調 |
| after\_insert | `insert`操作成功后回調 |
| after\_update | `update`操作成功后回調 |
| after\_delete | `delete`操作成功后回調 |
使用下面的方法注冊數據庫查詢事件
~~~
\think\facade\Db::event('before_select', function ($query) {
// 事件處理
return $result;
});
~~~
同一個查詢事件可以注冊多個響應執行。查詢事件在新版里面也已經被事件系統接管了,因此如果你注冊了一個`before_select`查詢事件監聽,底層其實是向標識為`db.before_select`的事件注冊了一個監聽。
>[danger] 查詢事件的方法參數只有一個:當前的查詢對象。但你可以通過依賴注入的方式添加額外的參數。
## 模型事件
模型事件是指在進行模型的查詢和寫入操作的時候觸發的操作行為。
>[danger] 模型事件只在調用模型的方法生效,使用查詢構造器操作是無效的
模型支持如下事件:
|事件|描述|事件方法名|
|---|---|---|
|after_read | 查詢后 |onAfterRead|
|before_insert | 新增前 |onBeforeInsert|
|after_insert | 新增后 |onAfterInsert|
|before_update | 更新前 |onBeforeUpdate|
|after_update| 更新后 |onAfterUpdate|
|before_write| 寫入前 |onBeforeWrite|
|after_write | 寫入后 |onAfterWrite|
|before_delete | 刪除前 |onBeforeDelete|
|after_delete | 刪除后 |onAfterDelete|
|before_restore | 恢復前 |onBeforeRestore|
|after_restore | 恢復后 |onAfterRestore|
注冊的回調方法支持傳入一個參數(當前的模型對象實例),但支持依賴注入的方式增加額外參數。
>[info] 如果`before_write`、`before_insert`、 `before_update` 、`before_delete`事件方法中返回`false`或者拋出`think\exception\ModelEventException`異常的話,則不會繼續執行后續的操作。
### 模型事件定義
最簡單的方式是在模型類里面定義靜態方法來定義模型的相關事件響應。
~~~
<?php
namespace app\index\model;
use think\Model;
use app\index\model\Profile;
class User extends Model
{
public static function onBeforeUpdate($user)
{
if ('thinkphp' == $user->name) {
return false;
}
}
public static function onAfterDelete($user)
{
Profile::destroy($user->id);
}
}
~~~
參數是當前的模型對象實例,支持使用依賴注入傳入更多的參數。
### 模型事件觀察者
如果希望模型的事件單獨管理,可以給模型注冊一個事件觀察者,例如:
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $observerClass = 'app\index\observer\User';
}
~~~
`User`觀察者類定義如下:
~~~
<?php
namespace app\index\observer;
use app\index\model\Profile;
class User
{
public function onBeforeUpdate($user)
{
if ('thinkphp' == $user->name) {
return false;
}
}
public function onAfterDelete($user)
{
Profile::destroy($user->id);
}
}
~~~
>[info] 觀察者類的事件響應方法的第一個參數就是模型對象實例,你依然可以通過依賴注入傳入其它的對象參數。
- 值得升級到5.1的18個理由
- 5.1.7版本新特性
- JSON字段類型在ORM中的使用
- 文件下載響應對象
- 教你使用5.1的數組對象查詢
- 模型三大利器之一:搜索器
- 在ThinkPHP中使用Yaconf
- 掌握命令行的表格輸出
- 5.1.25查詢參數綁定的改進
- ThinkPHP安全規范指引
- 巧用數據集的排序功能實現統計排序
- think-orm ——基于5.1的獨立ORM庫
- think-template——基于ThinkPHP的獨立模板引擎
- ThinkPHP5.1.26版本發布——修正版本,包含安全更新
- ThinkPHP5.0和3.2再發安全更新
- 官宣:ThinkPHP發布首個LTS版本
- 你真的了解Db類和模型的正確使用姿勢么?
- 如何更有效的記錄和管理日志
- 模型三大利器之二:修改器
- ThinkPHP5.1.28版本發布——修正上一版本問題,改進關聯查詢
- 模型三大利器之三:獲取器
- API版本控制的幾種思路
- ThinkPHP5.2第一個Beta版本發布測試
- 讓你少犯錯的數據查詢基本原則
- ThinkPHP發布5.1.29版本——常規更新
- 這15個好習慣讓你更容易升級到5.2
- 如何有效提高ThinkPHP的應用性能
- 讓你提高開發效率的查詢技巧
- 模型關聯查詢不完全指南
- 5.2發布Beta2版本——統一和精簡大量用法
- ThinkPHP發布5.1.30版本——支持微秒時間字段寫入
- ThinkPHP的數據緩存使用
- ThinkPHP5.2安裝及入口文件
- ThinkPHP榮獲2018 年度最受歡迎中國開源開發框架第1名
- 5.1路由使用心得技巧
- ThinkPHP5.*版本發布安全更新
- ThinkPHP項目及代碼規范指北
- 5.2版本的設計規范指導
- ThinkPHP5.1.32版本發布——圣誕快樂
- 利用Trait特性給模型增加樂觀鎖功能
- 5.2數據庫和模型的變化(摘要)
- ThinkPHP模板引擎實現和常見問題
- ThinkPHP5.0.24版本發布——安全更新
- 不忘初心,方得始終——ThinkPHP十三周年報告
- ThinkPHP5+相關資源匯總
- 異步社區ThinkPHP周年慶專享優惠活動
- 5.2路由的調整和改進
- ThinkPHP發布5.1.33版本——包含安全更新
- ThinkPHP擴展開發指南
- ThinkPHP發布5.2Beta3版本
- ThinkPHP發布5.1.34版本——喜迎新年
- ThinkPHP發布5.2RC1版本
- ThinkPHP發布5.1.35版本——常規更新
- 5.2配置類的調整
- 5.2時間查詢的改進和優化
- 5.2RC版本升級不完全指導(僅供學習參考)
- ThinkPHP5.2版本正式變更為6.0版本
- ThinkPHP百度云云虛擬主機專享免費活動
- 事件系統以及查詢事件、模型事件的使用
- ThinkPHP6.0RC2版本發布——架構升級、精簡核心
- ThinkPHP5.1.36LTS版本發布——常規更新
- 新版Session和Cookie設計變化
- ThinkPHP5.1.37版本發布——常規更新
- ThinkPHP6.0RC3版本發布——細節完善,體驗優化
- 6.0中間件使用詳解
- Composer各大廠商鏡像地址
- ThinkPHP6.0發布計劃公告
- 「ThinkPHP開發者周刊」招募志愿者
- ThinkPHP6.0日志變化
- ThinkPHP5.1.38版本發布——常規更新
- ThinkPHP6.0RC4版本發布——ORM獨立,日志多通道支持
- ThinkORM2.0開發指南上線
- ThinkPHP6.0RC5版本發布——多應用模式獨立,中間件機制調整
- ThinkPHP6.0版本發布——程序員節福利
- ThinkPHP5.1.39LTS版本發布——常規更新
- ThinkPHP6.0.1版本發布——圣誕快樂!
- 回顧2019,展望2020!
- ThinkPHPV6.0.2版本發布——2020新春快樂!
- 周年福利系列:Swoole合作優惠
- 億速云成為ThinkPHPV6.0獨家贊助發布商??
- 新冠疫情工具和限免資源專題(保持更新中)
- 周年福利系列:創宇信用認證合作優惠
- 周年福利系列:碼云企業版限時10%優惠
- 周年福利系列:想天短說抵現優惠
- think-swoole直播:從零開始掌握swoole開發
- 周年福利系列:B2C開源電商ShopXO授權8折優惠
- 周年福利系列:LayuiAdmin 永久授權限時優惠
- ThinkPHP資源導航站上線——構建生態 服務未來
- ThinkPHP官方技術支持服務和應用服務市場上線公測
- ThinkPHP市場精選——推廣基本要素
- ThinkPHP市場精選——客服聊天專題
- ThinkPHPV6.0.3版本發布——端午安康
- ThinkPHP開發者扶持計劃
- 6.0.3版本關鍵更新及升級事項
- 「ThinkPHP開發者周刊」改版重啟
- ThinkPHP市場精選——企業建站專題
- ThinkPHP 提供統一API接口服務
- ThinkPHP市場精選——直播電商專題
- ThinkAPI服務SDK發布
- 官方服務市場啟用獨立子域名
- ThinkPHP市場精選——刷臉支付專題
- ThinkAPI推出會員服務計劃
- ThinkPHPV6.0.4版本發布——中秋國慶雙節快樂
- ThinkPHPV5.1.40版本發布——常規更新
- 1024程序員節福利走一波
- ThinkPHP V6.0.5版本發布——兼容Composer2.0
- 知識圖譜應用場景——源論技術沙龍
- ThinkPHP5.*版本改進Composer2.0的兼容
- 官方市場雙十一精選推薦
- 技術人做產品有機會么(文末送課程)
- 本周秒殺——古德云售后獲客營銷系統
- ThinkAPI服務更新——支持接口分組和PHP版本依賴調整
- PHP8新特性盤點
- PHP8新特性系列:構造器屬性提升使用及注意事項
- ThinkPHP2021新年寄語
- ThinkPHP V6.0.6&V5.1.41版本發布——兼容PHP8.0
- PHP如何更優雅地調用API接口
- ThinkPHP V6.0.7發布——修正版本
- ThinkAPI服務更新——IP白名單
- 最新版ThinkORM對于時間字段的調整
- ThinkAPI短信接口正式上線
- ThinkPHP V6.0.8版本發布——多環境變量配置支持
- 頂想云寫作服務開啟第一次公測
- ThinkSSL上線——官方SSL/TLS證書服務
- MDBootstrap國內用戶福利——ThinkPHP官方市場首發
- ThinkPHP V6.0.9版本發布——常規更新
- ThinkORM功能盤點——虛擬模型
- 全面支持主流GIT版本庫——云寫作服務第二次公測
- 云寫作服務私有化部署方案之:版本庫私有化
- 看云雙十一活動
- ThinkPHP V6.0.10LTS發布——兼容PHP8.1
- ThinkPHP V6.0.12發布——命令行兼容8.1
- 頂想云知識管理上線公測——構建企業文檔中心和知識庫
- 頂想云上線——助力生態數字化建設
- 618活動進行中——官方市場迎來一波更新
- 頂想云知識管理正式上線——看云文檔啟動遷移服務
- ThinkPHP V6.0.13發布——常規更新
- 頂想云網站助理服務上線——構建產品支持服務
- ThinkPHP發布6.1.0&6.0.14版本——安全更新
- ThinkPHP新版社區上線試運營
- ThinkAPI上架人臉核身接口——助力網站實名認證
- 辭舊迎新——舊版社區停止注冊及發帖
- ThinkPHP6.1.2版本發布——兼容PHP8.2