🕵🏾

【Laravel9】Collectionクラスの中身を見る~onlyメソッド編~

2023/02/14に公開

はじめに

配列を操作するためのラッパークラスであるIlluminate\Support\CollectionクラスにはLaravel9では139個ものメソッドがあります。
Laravelを使用していたら見かけるであろう、map()やpluck()、merge()はCollectionクラスのメソッドです。

公式ドキュメントも貼っておきます。

https://readouble.com/laravel/9.x/ja/collections.html

今回はonlyメソッドが何をしているのか見ていきます。

環境

  • Windows11(WSL2)
  • PHP 8.2.1
  • Laravel 9.50.1
  • sail 2.6.1

onlyメソッドとは

only()はコレクションの中から指定したアイテムだけを返すメソッドです。

動作確認

$collect = collect([
    'name' => 'A',
    'height' => 175,
    'weight' => 70,
    'gripStrength' => 55,
]);

$result = $collect->only(['name', 'weight']);

dd($result);

nameとweightをキーとするアイテムのみ返ってきます。

Illuminate\Support\Collection {#275 ▼
  #items: array:2 [▼
    "name" => "A"
    "weight" => 70
  ]
  #escapeWhenCastingToString: false
}

onlyメソッドの中身

Illuminate\Support\Collection::only

Collectionクラスのonlyメソッドのは以下のようになっています。

public function only($keys)
{
    //①
    if (is_null($keys)) { 
        return new static($this->items);
    }

    //②
    if ($keys instanceof Enumerable) {
        $keys = $keys->all();
    }

    //③
    $keys = is_array($keys) ? $keys : func_get_args();

    //④
    return new static(Arr::only($this->items, $keys));
}

①引数$keysにnullが渡ってきたときはコレクションをそのまま返します。

②Enumerableはインターフェースなので、$keysのインスタンスがEnumerableインターフェースを継承しているクラスであればtrueになり、そのクラスのallメソッドを返します。

例えば、Illuminate\Support\CollectionクラスはEnumerableインターフェースを継承しているので$collect->only(collect(['name']))のような引数を入れても動作します。

③引数$keysが配列である場合は問題ないとして、配列でない場合はfunc_get_args()が呼び出されています。

func_get_args()は不特定の数の引数を配列として受け取ることができる関数です。
そのため$collect->only('name', 'height')と配列でない引数を渡しても③のところで$keysへ配列にして渡してくれます。

https://www.php.net/manual/ja/function.func-get-args.php

④Illuminate\Support\Arrクラスのonlyメソッドをインスタンス化してreturnしているので、追ってみます。

Illuminate\Support\Arr::only

Arrクラスのonlyメソッドは以下のようになっています。

public static function only($array, $keys)
{
    return array_intersect_key($array, array_flip((array) $keys));
}

array_intersect_key()は複数の配列の中から共通のキー名を見つけて、その共通のキーの配列を返す関数です。
引数に3つ以上配列を入れても全ての配列の共通キーを探します。

https://www.php.net/manual/ja/function.array-intersect-key.php

配列同士のキーを比較したいのですが、$keysは

array:2 [0 => "name"
  1 => "height"
]

となっています。そのためarray_flip()でキーと値を反転させてあげます。

https://www.php.net/manual/ja/function.array-flip.php

これでコレクションから引数で指定したキーのみを返すようになります。

まとめ

Collectionクラスのonlyメソッドでは、内部的にIlluminate\Support\Arrのonlyメソッドを呼んでいて、
標準関数のarray_intersect_key()やarray_flip()を使用していることが分かりました。

Discussion