>[danger] 官方已經在前不久發布了ThinkPHP`5.1.7`版本,`5.1`版本相較于`5.0`版本而言,本身更加嚴謹和規范,更接近主流設計思想。近半年來,`5.1`版本更新頻繁,此次最新版本更是帶來了很多的新特性。正在或者打算使用`5.1`版本的朋友可以關注下了,因為經過此次更新后,`5.1`版本也進入穩定階段了,基本上不太會有大的調整了。
最新版本(`V5.1.7`)的主要新特性主要包含:
[TOC=2,2]
## 引入中間件支持
關于中間件想必很多開發者已經在其它的主流框架中了解到了,ThinkPHP`5.1`版本最開始沒有引入中間件的原因是考慮到用戶需要了解新的知識概念和用法,同時容易和原來的行為用法相混淆。
>[info] 為了更規范開發和最大程度的公用某些組件,新版正式引入中間件支持。
原來你可能需要在控制器的初始化方法中添加相類似的代碼,現在你可以把這些代碼從控制器中獨立出來,方便更多的模塊調用和重用。如果你原來使用的是行為來進行處理的話,那么是否決定也改為中間件完全取決于你自己,因為仍然可以兼容運行(至少在`5.1`版本中不會變化)。
中間件的基本用法我大概介紹下:
### 定義中間件
可以通過命令行指令快速生成中間件類
~~~
php think make:middleware Check
~~~
這個指令會 `application/http/middleware`目錄下面生成一個`Check`中間件,也就是說默認生成的中間件的命名空間都是`app\http\middleware`,這個必須注意。
~~~
<?php
namespace app\http\middleware;
class Check
{
public function handle($request, \Closure $next)
{
}
}
~~~
中間件的入口執行方法必須是`handle`方法,而且第一個參數是`Request`對象,第二個參數是一個閉包。
>[danger] 中間件`handle`方法的返回值必須是一個`Response`對象。
### 前置/后置中間件
中間件是在請求具體的操作之前還是之后執行,完全取決于中間件的定義本身。
下面是一個前置行為的中間件
~~~
<?php
namespace app\http\middleware;
class Before
{
public function handle($request, \Closure $next)
{
// 添加中間件執行代碼
return $next($request);
}
}
~~~
下面是一個后置行為的中間件
~~~
<?php
namespace app\http\middleware;
class After
{
public function handle($request, \Closure $next)
{
$response = $next($request);
// 添加中間件執行代碼
return $response;
}
}
~~~
### 注冊中間件
第一種方式:注冊全局中間件
你可以在應用目錄下面定義`middleware.php`文件,使用下面的方式:
~~~
<?php
return [
\app\http\middleware\Auth::class,
'Check',
'Hello',
];
~~~
中間件的注冊應該使用完整的類名,如果沒有指定命名空間則使用`app\http\middleware`作為命名空間。
全局中間件的執行順序就是定義順序。可以在定義全局中間件的時候傳入中間件參數,支持兩種方式傳入。
~~~
<?php
return [
[\app\http\middleware\Auth::class, 'admin'],
'Check',
'Hello:thinkphp',
];
~~~
上面的定義表示 給`Auth`中間件傳入`admin`參數,給`Hello`中間件傳入`thinkphp`參數。
### 路由中間件
最常用的中間件注冊方式是注冊路由中間件
~~~
Route::rule('hello/:name', 'hello')
->middleware('Auth');
~~~
或者使用完整的中間件類名
~~~
Route::rule('hello/:name', 'hello')
->middleware(app\http\middleware\Auth::class);
~~~
支持對路由分組注冊中間件
~~~
Route::group('hello', function(){
Route::rule('hello/:name', 'hello');
})->middleware('Auth');
~~~
如果需要傳入額外參數給中間件,可以使用
~~~
Route::rule('hello/:name', 'hello')
->middleware('Auth:admin');
~~~
如果使用的是常量方式定義,可以在第二個參數傳入中間件參數。
~~~
Route::rule('hello/:name', 'hello')
->middleware(Auth::class, 'admin');
~~~
>[danger] 中間件方法參數只能有一個,但可以支持任意類型,在`handle`方法的第三個參數傳入即可。
如果你不希望每次在路由中注冊完整的類名,還可以在應用配置文件`middleware.php`中進行中間件的預定義,指定中間件的別名。
~~~
return [
'auth' => 'app\http\middleware\Auth',
'check' => [
'user' => app\common\middleware\CheckUser::class
],
];
~~~
然后,在路由中使用別名注冊中間件。
~~~
Route::rule('hello/:name', 'hello')
->middleware(['auth', 'check.user']);
~~~
好了,更多的中間件用法還需要你親自實踐。
## 路由改進和提速
新版本的路由改進是最多的(幾乎整個過年都在調整路由組件^_^),我們知道路由無非是兩大要點,路由定義和路由檢測。
路由定義涉及到一個規范化的問題,新版路由在保持原來的用法前提下,內部做了一些架構和細節的調整,使得路由的用法更加對象化。如果你看源碼的話,就會發現核心類庫的`route`目錄下面新增了幾個類。
### 路由規則的變量用法改進
路由定義方面主要對域名路由和路由分組的功能進行了強化,以及路由規則的更靈活定義。
之前的路由規則中變量分兩種,普通變量和組合變量定義,新版把這兩種合二為一了(也就是說兩種變量沒有任何區別,僅僅是表現方式不同,而且是出于兼容考慮)。你現在完全可以在路由規則中以任何方式定義路由變量。
例如你可以使用下面的路由規則而不用管目前的URL分隔符是什么:
~~~
Route::rule('item/:name_:id', 'order/index');
Route::rule('product-<category>:name', 'product/item');
~~~
另外,新版路由定義兩種變量方式`:name`和`<name> `可以混合使用,但建議統一使用`<name>`,在性能上略有優勢(實際上,最終解析的時候系統會統一解析成后者)。
### 路由匹配算法改進
路由檢測其實是最耗性能的,尤其是路由匹配這塊,因為基本上都是采用的正則匹配。在`5.1.6`版本之前,如果定義了100個路由,那么最后的那個路由規則可能需要遍歷100次才能正確匹配到路由,而且每個路由規則中的路由變量都是單獨匹配的,所以這個路由匹配的性能開銷是隨著路由定義的數量指數上升的。
`5.1.6`版本開始,系統對路由的匹配這塊進行了算法優化,靈感來自于`fastRoute`。基本思想是分兩個步驟優化(思想其實很容易懂,但技術層面比較復雜,所以想了解怎么實現的話還是仔細看代碼吧~本文只闡述思想)。
第一個步驟是對單個路由規則的匹配算法進行調整,不按照變量進行多次匹配,而是把路由變量的正則合并到一起,然后整個路由規則只匹配一次(如果這個路由規則都是靜態的,那么基本上不需要正則匹配,采用的是更快的非正則檢測方式)。這個是新版默認就開啟的,相比較之前的版本,性能已經提升明顯。
但路由的性能提速遠非如此簡單,第二個步驟的優化策略是如果當前匹配的路由分組下面有多個路由規則(確切的說是滿足當前請求類型的),則把這些滿足條件的路由規則合并成一個正則表達式進行路由匹配。如果你的路由分組下面有100個滿足條件的路由規則,如果要訪問最后的路由規則,之前的方式可能需要遍歷100次,而新版只需要進行一次匹配。就算加上路由規則的合并開銷,仍然是值得的。
如果需要使用分組路由規則的全局合并檢測,需要開啟下面的設置(另外一個方式是單獨對某個路由分組使用`mergeRuleRegex`方法,這種需求應該不多):
~~~
// 合并分組路由規則
'route_rule_merge' => true,
~~~
那么到這是不是就結束了呢?不要忘了ThinkPHP`5.1`的路由有一個很創新的地方就是延遲解析,主要體現在路由分組或者域名路由。通常的路由定義是需要把定義的路由進行一次解析處理,然后保存成我們方便檢測的一個數據結構或者對象,但由于WEB請求的特殊性,每次請求都需要重復這種路由定義的解析過程,為了降低路由解析的開銷,ThinkPHP只會在路由分組匹配之后才會實際去進行該路由分組下面的路由解析過程,然后再進行后續的路由檢測,如果你的分組下面還有子分組,那么繼續按照這個方式解析。
不過路由的延遲解析功能默認是關閉的,可以在應用配置中開啟:
~~~
// 開啟路由延遲解析
'url_lazy_route' => true,
~~~
通過這三個步驟的優化,我相信現在你應該明白如何利用路由規則的合并以及路由的延遲解析機制來提升你的路由性能了吧。
如果你繼續深入路由的使用,還會發現一些細節的用法。
## 查詢安全性改進
接下來要講的是新版對于查詢安全性的一個改進,引入了一個新的`Expression`類,對于這種類型的數據,在查詢和寫入操作的時候會保持原樣`SQL`(比較適合于使用SQL函數的情況),并且同時支持參數綁定功能。
為了方便,`Query`類增加了`raw`方法用于實例化一個`Expression`對象,我們可以這樣使用:
~~~
Db::name('user')
->field(Db::raw('id, name'))
->where(Db::raw('id > :id AND status = 1'), ['id' => 1])
->order(Db::raw('id desc'))
->select();
~~~
系統在解析的時候,支持對`field/where/order`方法的`Expression`對象的解析。
同時為了方便使用,提供了一些快捷方法,例如上面的例子可以改為:
~~~
Db::name('user')
->fieldRaw('id, name')
->whereRaw('id > :id AND status = 1', ['id' => 1])
->orderRaw('id desc')
->select();
~~~
> 當然,大部分情況下,系統會自動判斷是否需要使用`Expression`表達式對象,從而避免數據出現安全隱患。例如,當你使用字符串條件,并且包含空格和函數用法的話,會自動解析為`Expression`對象執行查詢。
在數據寫入方面一樣可以利用表達式方式來杜絕可能的安全隱患,例如:
~~~
Db::name('user')
->save($data);
~~~
當你的`data`數據直接來自于表單提交數據的時候,會導致SQL注入的可能,新版會檢查數組數據的安全性,對`exp`表達式寫入進行更嚴格的類型檢查。
原來的`exp`數組用法將不可用,而必須改為:
~~~
Db::name('user')
->where('id', 1)
->save([
'score' => ['exp', Db::raw('score+1')],
]);
~~~
或者直接使用`exp`方法更新數據
~~~
Db::name('user')
->where('id', 1)
->exp('score', 'score+1')
->save();
~~~
這些查詢的安全特性同樣對模型適用,比如你需要使用SQL更新數據的時候,可以使用
~~~
$user = User::get(1);
$user->name = Db::raw('UPPER("thinkphp")');
$user->score = Db::raw('score+1');
$user->save();
~~~
新版的特性暫時就介紹這么多,還有一些細節等待各位去挖掘和分享。
- 值得升級到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