背景
- 業務で管理画面にページネーション機能を持った一覧画面を作る、というシンプルなタスクに着手したときのこと
- 当初Laravelではおなじみの
pagineate
メソッドがあるので、これを使って書こうと構想していた - ただ、今のプロジェクトがLaravel-adminというライブラリを使用しており、paginateをforeachしてループさせて、別の変数に格納するという処理が必要だった
- そこで、
「プロジェクト内の同じページネーション機能を持った一覧表示画面はどう書いているんやろか?」
と確認してみると、、、
$orders = $user->orders()->paginate();
...
foreach ($orders->toArray()['data'] as $order) {
$id = $order['id']
...
}
「ん?!なんだこの
toArray()
は?['data']って何?」
となった
-
toArray()
自体の意味は知っていたが、ここに存在する理由が謎だった。 -
実際に、既存の
toArray
を消して以下のようにしてみたが
$orders = $user->orders()->paginate();
...
foreach ($orders as $order) { // 修正
$id = $order->id // 修正
...
}
- 機能として問題ない(むしろこっちのが見慣れた形なので、動かないと困る笑)
- これを調べた時の話
結論
- まず結論からいうと、静的解析でエラーになるというのが結論です。
詳細
- phpstanによる静的解析の結果は以下
Argument of an invalid type Illuminate\Contracts\Pagination\LengthAwarePaginator supplied for foreach, only
iterables are supported.
- 要約としては
「foreachはiterablesなものには使えるけど、今はLengthAwarePaginatorに使っていて、これには使えないよ」
といった感じ。
- ここでいう「iterablesなもの」というのは要はイテレータのことでざっくりいうと「反復可能なモノ」
- 具体的には配列、Collectionがイテレータこれに該当。
- そして
Illuminate\Contracts\Pagination\LengthAwarePaginator
というのはpaginate()
メソッドの戻り値のインスタンス- これは配列でもColllectionでもないオブジェクトになる、つまりイテレータではないので、エラーが発生する、ということ
本題
- 以上を踏まえて、冒頭のコードに戻ると
$orders = $user->orders()->paginate();
...
foreach ($orders->toArray()['data'] as $order) {
$id = $order['id']
...
}
1, $orders->toArray()
でLengthAwarePaginator
インスタンスを配列化(これで静的解析エラー回避)
2, その配列化した要素の内、取得したい値は['data']
にあるので、これを取得
3, foreachでループ処理
という流れになるということでした
所見
- 普段よく見かける
paginate()
の使い方は、以下を作って
$users = User::paginate(15);
Viewファイルに以下を書く
{{ $inquiries->links() }}
のが一般的かな、と思います。
- この静的解析結果がエラーになることを知り、Laravel内でもどっかで同じような処理してんのかな?と思って
links
メソッド内では特にforeachしてなさそうでしたね。。。
※ちなみに、静的解析も「どこまでエラーとして吐かせるか」というのはプロジェクトごとにレベルを変えれるので、今回のようなエラーが出ない可能性もあります。
余談ですが、、、
- 静的解析で今回のように直感的にわかりにくいコードが作られてしまうのは静的解析を採用することのデメリットかと思います。
- ただ、これによりプロジェクトが大規模化した際に起こりうるバグの温床を開発と同時並行でつぶし込めているのはかなり安心感があり大きなメリットです!
- 特にサービス寿命を長く持たせたい自社開発プロダクトであれば採用しておきたいところかな、と思いました。
- たまに「これ想定しなきゃダメ!?」みたいなのエラーももちらほらありますが、、、
- 結論、この静的解析を進めつつ開発を進めるのは個人的には賛成ですね。
※コレ、当たり前のモノだったらスイマセン。。。
ただ、気づきとして純粋に静的解析が便利だな、と思ったんです。。。