1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Laravel]paginate()後のforeachの注意点

Posted at

背景

  • 業務で管理画面にページネーション機能を持った一覧画面を作る、というシンプルなタスクに着手したときのこと
  • 当初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がイテレータこれに該当。

イテレータについて(PHP公式)

  • そして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してなさそうでしたね。。。

※ちなみに、静的解析も「どこまでエラーとして吐かせるか」というのはプロジェクトごとにレベルを変えれるので、今回のようなエラーが出ない可能性もあります。

余談ですが、、、

  • 静的解析で今回のように直感的にわかりにくいコードが作られてしまうのは静的解析を採用することのデメリットかと思います。
  • ただ、これによりプロジェクトが大規模化した際に起こりうるバグの温床を開発と同時並行でつぶし込めているのはかなり安心感があり大きなメリットです!
    • 特にサービス寿命を長く持たせたい自社開発プロダクトであれば採用しておきたいところかな、と思いました。
    • たまに「これ想定しなきゃダメ!?」みたいなのエラーももちらほらありますが、、、
  • 結論、この静的解析を進めつつ開発を進めるのは個人的には賛成ですね。

※コレ、当たり前のモノだったらスイマセン。。。
ただ、気づきとして純粋に静的解析が便利だな、と思ったんです。。。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?