# Laravel:深入Query/Builder ###### tags: `laravel` laravel 大部分對 **Eloquent/Builder** 的呼叫都會透過 ==__Call== 委託給 **Query/Builder** 執行。 所以大部分時候要查有哪些函式可以用,往往是直接找 ==\Illuminate\Database\Query\Builder== 這檔案即可。 ## :memo: Marcroable 而Query/Builder檔案在開頭就引入了 **Macroable** 這個 trait。 進一步追蹤這個檔案的話(==\Illuminate\Support\Traits\Macroable==), 會注意到它有一個 **$macros** 關聯陣列(以 function name 為 key;以 callable 為 value), 用來為引入這個 trait 的 class 動態擴充可執行的函式。 ### 擴充 Query/Builder 你可以試著在 AppServiceProvider 的 ==boot()== 裡面這樣做: 底下為 Query/Builder 新增了一個, 一次可以新增好幾筆排序條件的,強化版 ==orderBy==。 其中 macro() 的參數分別是: 1.**Function name** 2.**Callable** 其中 Callable 的參數便是你在呼叫這個函式時需要傳入的參數,不多不少。 ```php= <?php $keys = ['name', 'created_at']; $sorts = ['asc', 'desc']; Builder::macro('orderByMany', function ($keys, $sorts) { $rules = array_combine($keys, $sorts); foreach ($rules as $key => $rule) { $this->orderBy($key, $rule); } }); ``` **$this ???** 根據 [php 官方的介紹](https://www.php.net/manual/en/language.oop5.basic.php), **$this 通常會指向呼叫他的 method 所在的 Object。** 所以因為如此, 在這個透過 macro 擴充的 function 之中呼叫 **$this** , 也總是會指向一個 **Class 是 Query/Builder 的物件。** 所以才能透過它直接執行 ==orderBy==。 ### __call 一般你在用 eloquent 串 sql 的時候, 如果是執行已經存在的函式那就直接執行沒問題。 但當你執行**一個不存在的函式** , 呼叫會首先被導到 ==__call== 額外做處理。 首先它會檢查,你要執行的函式是不是透過 macro 擴充的,有則執行。 沒有就繼續檢查,你要執行的函式是不是以「where」作為開頭的,有則執行 ==dynamicWhere()==。 上面兩者都沒有,便會丟出一個 ==BadMethodCallException==。