5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravel v11.37.0でのCollection::hasAnyメソッドの挙動の変化

Last updated at Posted at 2025-10-18

はじめに

  • YUZURIHAの松村です。
  • 先日Laravelをv11.37.0へアップデートした際にハマったポイントがあったので、紹介します。

Collection::hasAnyメソッドとは?

  • まず、今回ハマってしまったCollection::hasAnyとはどんなメソッドなのかを解説します。
  • 一言で言うと、引数に指定したキーのいずれかがCollection内に存在するかどうかを判断するメソッドです。
  • 具体的にどのように使うかは、Laravel公式の以下のページをご参照ください。

Laravel v11.37.0でのCollection::hasAnyメソッドの変更

  • そしてLaravel v11.37.0には、こちらのPRの変更が含まれています。

  • PRの説明としては以下の通り記載されているため、あくまでもCollection::hasAnyメソッドにおける型ヒントの修正とリファクタリングのように見えます。
    • Update hasAny's type hint to match has. Also inlines the call to has with array_key_exists.
    • 和訳: hasAnyの型ヒントをhasと一致するように更新します。また、hasの呼び出しをarray_key_existsでインライン化します。
  • 「破壊的な変更がある」や「挙動が変わる」という旨の記述はどこにもありません。
  • しかし!実際にv11.37.0にアップデートしてCollection::hasAnyメソッドを呼び出すと、挙動が変わっていました!😱ギャー

どのように挙動が変わったのか?

  • 挙動が変わってしまうのは、第一引数に二次元配列を指定した場合でした。
  • 具体的にどう変わったのかTinkerを使って見て行きます。

v11.36.0

  • falseが返ります。
    > collect(['test1' => 'hoge'])->hasAny(['test1' => ['test1-1'], 'test2' => ['test2-1']])
    = false
    

v11.37.0

  • array_key_exists関数の引数でTypeErrorとなってしまいます。
    > collect(['test1' => 'hoge'])->hasAny(['test1' => ['test1-1'], 'test2' => ['test2-1']])
    
       TypeError  array_key_exists(): Argument #1 ($key) must be a valid array offset type.
    

なぜ変わったのか?

v11.36.0

  • v11.36.0までは、Collection::hasAnyメソッドの内部でCollection::hasメソッドを呼び出していました。

  • hasAnyメソッド内でループしてhasメソッドを呼び出し、更にhasメソッド内でもループしてarray_key_exists関数を呼び出しています。
  • この処理によって、二次元配列でも正常に処理されてfalseが返されていました。

v11.37.0

  • v11.37.0では、hasメソッドを使わずに直接array_key_exists関数を呼び出すようになりました。

  • これよってarray_key_exists関数の第一引数に配列が入ってしまい、TypeErrorとなってしまいました。

正しい挙動

  • 冒頭でも述べたように、Collection::hasAnyは「指定したキーのいずれかがCollection内に存在するかどうか」を判定するメソッドです。
  • そのため、一次元配列でキーを指定することが前提となっており、二次元配列を指定するのはイレギュラーな使い方と考えられます。
  • そう考えるとv11.36.0までの「エラーにならずfalseが返る」という挙動はおかしくて、v11.37.0以降の「エラーになる」という挙動が正しいとも言えます。
  • ただLaravel公式のドキュメントやPR・CHANGELOGにはその旨の説明は無いので、説明が欲しかったなと思ってしまいますね😅

最後に

  • 今回エラーになったCollection::hasAnyの呼び出し箇所については、「意図して第一引数に二次元配列を指定していた」わけではなく「一次元配列を指定しているつもりが、ある条件の時だけ二次元配列になってしまう」というものでした。
  • テストについては、一次元配列になる正常系のテストケースはあったものの、二次元配列になってしまう異常系のテストケースはありませんでした。
  • そのため、テスト実行時にはこのエラーに気付くことができませんでした。
  • やはり「異常系も含めたテストカバレッジを上げておいて、アップデート時にはテストがオールグリーンになるようにする」というのは大切ですね。
5
0
0

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
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?