40秒で把握するCollectionのafter()

Laravel11公式ドキュメントのCollectionメソッド after()についてみていきます。段階的に見ていきますが、LaravelのCollectionについて把握していない方は、以下の記事を先に見るとこの記事が読みやすくなると思います。

LaravelのCollectionに触れる

この記事で得られること

  • Collectionメソッドのafter()を把握できる
  • Laravelのソースコードを読む体験ができる

メソッドの概要を見る

Laravel – The PHP Framework For Web Artisans

公式ドキュメントを日本語訳してからの引用

**afterメソッドは、指定された項目の次の項目を返します。null**指定された項目が見つからないか、最後の項目である場合は、 が返されます。

$collection = collect([1, 2, 3, 4, 5]);
 
$collection->after(3);
 
// 4
 
$collection->after(5);
 
// null
  • afterメソッドは指定された項目の次の項目を返す
  • 指定された項目が見つからない or 指定された項目が最後の場合はnullが返る

このメソッドは、「緩い」比較を使用して指定された項目を検索します。つまり、整数値を含む文字列は、同じ値の整数と等しいとみなされます。「厳密な」比較を使用するには、**strict**メソッドに引数を指定します。

collect([2, 4, 6, 8])->after('4', strict: true);
 
// null
  • afterメソッドは緩い比較で指定された項目を検索する
  • 厳密な比較にはstrictメソッドに引数を指定する

あるいは、独自のクロージャを提供して、特定の真理値テストに合格する最初の項目を検索することもできます。

collect([2, 4, 6, 8])->after(function (int $item, int $key) {
    return $item > 5;
});
 
// 8

少しこんがらがりましたが、afterは該当する項目の次の値を返すので5より上の6の次の値である8を返すというわけですね。

メソッドのソースを見る

概要は何となく掴めてきたので早速ソースを見ていきます。

vendor/laravel/framework/src/Illuminate/Collections/Collection.php

    /**
     * Get the item after the given item.
     *
     * @param  TValue|(callable(TValue,TKey): bool)  $value
     * @param  bool  $strict
     * @return TValue|null
     */
    public function after($value, $strict = false)
    {
        $key = $this->search($value, $strict);

        if ($key === false) {
            return null;
        }

        $position = $this->keys()->search($key);

        if ($position === $this->keys()->count() - 1) {
            return null;
        }

        return $this->get($this->keys()->get($position + 1));
 

CursorAI(GPT4)に聞いて分かったことも交えつつ解説します。

$key = $this->search($value, $strict);

$this→ の部分はafterメソッドを呼び出すコレクションの事を指しています。

元のコレクションからsearch()メソッドを呼び出し、引数に$valueを入れることで$valueがコレクションのどの位置にあるかを$keyとして取得しているようです。

👉$strictのデフォルト引数がtrueの場合は型も含めて厳密な検索を行うようです。

if ($key === false) {
    return null;
}

$keyが$valueの位置を指します。$valueが存在しない場合$key === false が成立してnullが返されます。

$position = $this->keys()->search($key);

$valueが元のコレクションの何番目にあるかを探しています。

ここで、$keyも$positionも同じ該当項目の位置を取得しているように見えますが違いは何か気になったので、CursorAI(GPT-4)に聞いてみたところ、以下のような違いがあるようです。

違い
$key は、値がコレクション内でどのキーに紐づいているかを特定します。これは、値に基づいた検索です。
$position は、そのキーがキーのリストの中でどの位置にあるかを特定します。これは、キーに基づいた順序を確認するためです。
この2つのステップを経て、コレクション内のアイテムの相対的な位置を正確に把握し、次のアイテムを取得することが可能になります。

$keyで$valueがコレクション内のどのキーに紐付くかを取得し、$keyを使ってCollection内の$valueがどの位置にあるかを取得しているという事ですね。

if ($position === $this->keys()->count() - 1) {
    return null;
}

$valueがコレクションの最後の項目かどうかを確認しているようです。最後の項目の場合は次のアイテムが無いのでnullを返します。

return $this->get($this->keys()->get($position + 1));

$valueが最後のアイテムでない事は先のif文で確認済みなので、$afterの機能である「該当する項目の次の項目を返す」を実行しています。$positionが該当する項目の位置を指し、+1して次の位置を指しているというわけですね。

まとめ

コレクションのafterメソッドは以下のような特徴を持つ

  • 第一引数で指定された項目の次の項目を返す
  • 第二引数のデフォルト引数にtrueを渡すことで厳密な比較が可能

少し説明がくどくなってしまいましたが、これ以上無いくらいに細かく見ていくと意外と見落としていることが多くあるということに気付けました。

また、コレクションメソッドの中でコレクションメソッドが使われていることもあるということも知れました。今回使われていたsearch()とkeys()がどんな実装なのかも別の機会に見てみたいと思います。

おまけ CursorAI(GPT-4)に聞いたときに使った質問文

1ラウンド目

下記のコードの解説を以下の点を踏まえてお願いします。
- 段階的に行う
- 小学生でも分かるような言葉を使う
- コードの引用を混じえる

"""
    /**
     * Get the item after the given item.
     *
     * @param  TValue|(callable(TValue,TKey): bool)  $value
     * @param  bool  $strict
     * @return TValue|null
     */
    public function after($value, $strict = false)
    {
        $key = $this->search($value, $strict);

        if ($key === false) {
            return null;
        }

        $position = $this->keys()->search($key);

        if ($position === $this->keys()->count() - 1) {
            return null;
        }

        return $this->get($this->keys()->get($position + 1));
    }
"""

2ラウンド目

$key の取得と $positionの取得ではどちらもアイテムの位置を取得しているようですが、何が違うのでしょうか?

コメント

タイトルとURLをコピーしました