背景
- Laravelプロジェクトアサイン当初、VSCodeの拡張機能
PHP Intelephense
により、知らないメソッドはよくジャンプしてvender/laravel配下を読みに行くことが多かった - そんな中、以下コードを見た
$query->whereLike('code', $this->input)
- この
whereLike
というメソッドを見て
「LaravelはLIKE検索もできるwhere句もあるんだ~」
とのんきにPHP Intelephense
でジャンプしようと思ったらできない。
おや?
ジャンプできない理由は謎だったが、ドキュメントを確認すると、whereLike
なんてメソッドはない…
- よくよく調べるとプロジェクト内にこんなソースコードを発見
Builder::macro('whereLike',function...
「なんじゃこりゃ…?」
-
macro
というワードとそれ以降に書いてある(特に第2引数)コードの意味がよく分からんかったので、深く理解しようというのが今回の背景
目的
- macroを理解する
- ※きっかけとなったwhereLikeをわざわざ作った背景等はもう一つ上の次元なので、一旦割愛
- 気になる方は概要理解
https://qiita.com/take_3/items/1154ecbd8033a9a3beaf
環境
- Laravel 8.x
内容
前提
- 今回はmacroを知ったきっかけであるBuilderで理解進める
- Collectionにもmacroがあるらしい。
- こっちも利用頻度高いと思うので、取り上げる
概要
- まずは1次情報からということで公式ドキュメントで
8.x macro
で検索すると、8件のヒット(21/11現在)
- そもそも「マクロとは?」の答えは以下
関連する複数の操作や手順、命令などを一つにまとめ、必要に応じて呼び出すことができるようにする機能
※参考↓
https://e-words.jp/w/マクロ.html
- なるほど、意味を知ってしまえばそんな難しくない
- 「一つにまとめて、必要に応じて使う」といいう点からサービスコンテナの延長の概念だなと感じた
使い方-Builder
公式ドキュメントに沿って行く
ソースコード
マクロの登録
ExampleServiceProbiver.php
use Illuminate\\Support\\Facades\\Response;
use Illuminate\\Support\\ServiceProvider;
use Laravel\\Scout\\Builder;
/**
* 全アプリケーションサービスの初期起動処理
*
* @return void
*/
public function boot()
{
Builder::macro('count', function () {
return $this->engine->getTotalCount(
$this->engine()->search($this)
);
});
}
- 記述するのは場所はどこでもいいと思うが、一般的には公式と同じようにサービスプロバイダ―に記述することが多そう(推測)
- そうすれば、いつでも使いたい時に作ったメソッドを使用できるから
- Builderの場合は
Laravel\\Scout\\Builder
内にあるmacroメソッドを使う。引数は- 第2引数:メソッド名
- 第3引数:メソッドによる処理内容
マクロの使用
ExampleController.php
use App\\Models\\Order;
Order::search('Star Trek')->count();
- あとはどこでも使うだけ。
- すごく楽。
使い方-Collection
こちらも公式ドキュメントに沿って行く
ソースコード
マクロの登録
ExampleServiceProbiver.php
use Illuminate\\Support\\Collection;
use Illuminate\\Support\\Str;
Collection::macro('toUpper', function () {
return $this->map(function ($value) {
return Str::upper($value);
});
});
- 95%くらいbuilderと同じ
- Biulderと異なるのは
macro
メソッド本体の設定場所くらい
- Biulderと異なるのは
- 記述するのは場所はどこでもよさそう。(理由は上述の通り)
- Collectionの場合は
Illuminate\\Support\\Collection
内にあるmacroメソッドを使う。引数はBuilderと同じ以下の通り- 第2引数:メソッド名
- 第3引数:メソッドによる処理内容
- 今回は
toUpper
というメソッドをCollectionに対して使うことで、Collection内の文字列を大文字にするマクロを作った模様。
マクロの使用
- 使用もBuilderと同じ。
ExampleController.php
$collection = collect(['first', 'second']);
$upper = $collection->toUpper();
dump($upper)
// ↓出力結果
// ['FIRST', 'SECOND']
- 無事、小文字→大文字に変換されております。
補足
- 他にはレスポンスに対してマクロを登録したり、
- そのレスポンスをサービスプロバイダで依存注入(DI)してマクロ登録したり
結構いろんなところで使える。
- Laravelのみならず、macroと類似した機能は他の言語にも存在する
- C言語ではdefineという関数らしい
- https://www.sejuku.net/blog/25927
所見
ただの感想
- サービスプロバイダに記述するあたりなどみて
独自の処理をメソッドにギュッと凝縮していつでも使える感じにした「お手軽サービスコンテナ」だな
という直感的な感想です笑
- そもそも現状でもかゆいところに手が届くくらい、組み込み関数は充実している感があるが、
「使いたいやつないなら、自分で作って」
と言わんばかりにサービス精神あふれるLaravelはしゅごい。
引っかかる点
- ただ、Builderについては
スコープ
、Collectionについてはアクセサ
がある - 個人的主観としては、以下の使い分けのイメージ
- 汎用度が相対的に高い(=スコープが相対的に広い):
マクロ
- 扱うリソースが多岐にわたる(User, Order, Post…etc)
- 汎用度が相対的に低い(=スコープが相対的に狭い):
スコープ
、アクセサ
- 扱うリソースが限られている(User内だけとか)
- 汎用度が相対的に高い(=スコープが相対的に広い):
- ただ、そうなると、
マクロとサービスコンテナとの使い分けは?
とかの疑問がわくので、ここら辺は実務で使っていく中で言語化していこうと思います。