對於本文涉及到的資料查詢的幾個基本原則請盡量納入你的專案規範,也是官方倡議的最佳實踐。在此之前,我希望你已經看過之前的一篇部落格:「 你真的了解Db類別和模型的正確使用姿勢麼? 」。
盡量不要使用陣列條件查詢
大部分混亂的查詢語法都是使用了陣列查詢導致的,而5.1的陣列條件查詢用法又和5.0是完全不同的,如果你習慣了5.0的陣列查詢方式,建議你閱讀下這篇文章:「 教你使用5.1的陣列物件查詢 」。
下面可能是很多新手比較容易犯的一個查詢錯誤。
$where['id'] = ['in', '1,2,3']; User::where($where)->select();
顯然,這個查詢思維深受舊版的影響。 5.1版的查詢語法比較5.0來說,比較物件化,下面的這種才是正確的用法。
$where['id'] = [1,2,3]; User::where($where)->select();
也許是因為PHP的陣列太好用的緣故,很多人對陣列查詢條件樂此不疲(或是物件焦慮?)。但如果你正確的使用查詢建構器以及配合模型的相關特性,可以讓你的查詢邏輯變得更清晰,也更容易維護。
而且,在一些較為複雜的查詢條件下,你無法使用陣列完成查詢,例如下面的查詢用法。
User::where('id', '>', 100) ->whereOr('id', '<', 10) ->where('name', 'like', 'think%') ->whereColumn('name', 'nickname') ->when('80'== $condition, function ($query) { $query->where('score', '>', 80)->limit(10); })->select();
所以,除非你很清楚5.1的陣列查詢用法,否則請盡量不要用陣列條件查詢了。
安全使用字串查詢條件
在使用字串查詢條件的時候,如果存在外部變量,請務必使用參數綁定,並最好使用whereRaw方法,該方法可以和其它的查詢建構器方法混合使用。
User::whereRaw("id = :id AND name = :name", [ 'id' => [$id, \PDO::PARAM_INT] , 'name' => $name ])->where('status', 1) ->order('id', 'desc') ->select();
對於一些比較在意效能的查詢,你也可以直接使用query或execute方法,但同樣也要注意參數的安全性以及考慮不同資料庫的移植問題。
Db::query("select * from think_user where id=? AND status=?", [8, 1]); Db::execute("update think_user set name=:name where status=:status", ['name' => 'thinkphp', 'status' => 1]);
對使用了SQL函數的查詢採用Raw機制
#如果你的查詢裡麵包含了SQL函數,那麼請使用whereRaw(或whereExp)、orderRaw或者fieldRaw方法。
User::whereExp('nickname', "= CONCAT(name, '-', id)") ->orderRaw("field(name,'thinkphp', 'kancloud')") ->fieldRaw('id,SUM(score)') ->select();
合理運用閉包,但不要濫用
閉包查詢在查詢建構器中有一些特殊用途,但如非必要,也無需濫用。
閉包查詢的典型使用情境包括下面幾個。
條件查詢中通常都用閉包來表示一組條件查詢。
User::when($condition, function ($query) { // 满足条件后执行 $query->where('score', '>', 80)->limit(10); }, function ($query) { // 不满足条件执行 $query->where('score', '>', 60); })->select();
在一些子查詢中常會用到閉包。
User::whereIn('id', function ($query) { $query->table('profile') ->where('name', 'like', 'think%') ->field('id'); })->select();
產生一組閉合的查詢條件
User::where('id', '>', 100) ->whereOr(function($query) { $query->where('name', 'like', 'think%') ->whereColumn('name', 'nickname'); })->select();
在這個查詢用法中,閉包裡面的查詢條件會在兩邊加上括號而成為一個閉合的查詢條件。
在很多的關聯預載入查詢中可以透過閉包來進行關聯資料的篩選。
User::with(['profile' => function($query) { $query->field('user_id,email,phone'); }])->select([1,2,3]);
盡量重複使用你的查詢條件
所有的查詢條件應該做到一處定義多處復用,例如封裝到模型的方法裡面,尤其不要直接把一堆複雜的查詢條件寫到你的控制器程式碼,否則一旦業務調整,滿世界的搜尋程式碼改變你的查詢條件將會是一場噩夢。
你也許在官方的手冊或一些教學中看到很多在控制器裡面直接封裝查詢條件的寫法,但那僅僅是出於方便展示用法的需要,並不可取。
在一些中大型的應用架構設計中,通常會把模型分成資料層、邏輯層和服務層,控制器只會呼叫服務層方法。而查詢邏輯基本上被封裝到邏輯層裡面,資料層只是做模型的各種定義。
而在簡單的應用裡面,也可以採用PHP的Trait機制來實作程式碼的重複使用機制。
用查詢範圍或搜尋器簡化查詢
如果你使用模型查詢的話,把你的查詢條件盡量封裝到查詢範圍或搜尋器方法裡面,查詢範圍和搜尋器的差異主要在於查詢範圍比較適合定義一組(多個欄位)查詢條件,如果要調用多個查詢範圍需要多次調用,而搜尋器比較適合定義一個欄位(其實並非絕對)的查詢條件,只需要呼叫一次withSearch方法。
使用查詢範圍和搜尋器的範例。
<?php namespace app\index\model; use think\Model; class User extends Model { public function scopeVip($query) { $query->where('user_type', 'vip') ->where('status', 1) ->field('id,name'); } public function searchAgeAttr($query, $age) { $query->where('age','>',$age); } public function searchScoreAttr($query, $score) { $query->where('score','<=',$score)->where('score', '>' ,0); } }
控制器程式碼
<?php namespace app\index\controller; use think\Controller; use think\Request; class index extends Controller { public function index(Request $request) { // 查询VIP会员 User::vip()->select(); // 查询年龄和分数 User::withSearch(['age,'score''], $request->param())->select(); } }
在控制器程式碼中,我們只專注於業務邏輯本身,而不需要關注這個邏輯內部的查詢條件是什麼。更詳細的關於搜尋器和查詢範圍的內容可以參考官方手冊。
PHP中文網,有大量免費的ThinkPHP入門教學,歡迎大家學習!
本文轉自:https://blog.thinkphp.cn/833794
以上是ThinkPHP:資料查詢的基本原則的詳細內容。更多資訊請關注PHP中文網其他相關文章!