PHP Laravel Collectionの使い方!each/map/filter/whereを使いこなす

シェアしてね〜🤞

【Laravel】Collectionの使い方とよく使うメソッド

LaravelのCollectionとは

LaravelのCollectionは、PHPの配列をより便利に使うためのラッパークラスです。

PHPの配列だけでやると複雑になってしまうことを、メソッドを通して簡潔に行えます。

Collectionを生成する方法

collect()に配列を渡すことで、Illuminate\Support\Collectionインスタンスが生成されます。

$collection = collect([1, 2, 3, 4, 5]);

また、DBファサードやEloquentのクエリビルダーの結果がCollection(またはその拡張)です。

Collectionは「イミュータブル」

Collectionを使う上で注意点があります。

Collectionの多くのメソッドは、呼び出し元の配列に変更を加えず、新しいCollectionを返します(この特性をイミュータブルと表現します)

つまり、メソッドの返す値を変数で受け取らないと、変更が反映されません。

$collection = collect([1, 2, 3, 4, 5]);

// mapメソッドで各要素に2をかける
$multiplied = $collection->map(function ($item) {
    return $item * 2;
});

// $collectionの中身は[1, 2, 3, 4, 5]のまま
// $multipliedの中身は[2, 4, 6, 8, 10]

よく使うメソッド

Collectionには様々なメソッドがありますが、よく使う以下のメソッドの使い方を紹介します。

  • toArray
  • map
  • each
  • filter
  • where

toArray

Collectionは配列を内部に保持するラッパークラスであり、配列そのものではありません。

toArrayは配列そのものが欲しいときに使うCollectionのメソッドです。

$collection = collect([1, 2, 3]);

$arr = $collection->toArray();  // [1, 2, 3]

なお、allメソッドもCollectionの中身を配列として返してくれますが、toArrayと違いネストされたCollectionは配列になりません。

map

mapメソッドは、各要素にコールバック関数に書いた処理を加えて、値に変更が加わった新しいCollectionを生成します。

そのまま値を返すと変更が加わらないので、条件分岐などを使って柔軟な対応ができます。

例えば、Collection内の数値を2倍にした新しいCollectionを生成する場合は以下のようになります。

$collection = collect([1, 2, 3, 4, 5]);

$multiplied = $collection->map(function ($item, $key) {
    return $item * 2;
});

// $multipliedは[2, 4, 6, 8, 10]を持つ新しいCollection

each

eachメソッドは、各要素をクロージャに渡して反復処理します。

mapメソッドに似ていますが、新しいCollectionは返さず、また元の値にも影響を与えません。

$collection = collect([1, 2, 3, 4, 5]);

$collection->each(function ($item, $key) {
    echo "{$item}, ";
});

// 「1, 2, 3, 4, 5, 」がechoされる
// $collectionの中の配列は[1, 2, 3, 4, 5]のまま

filter

filterメソッドは、条件を満たす要素を選び出して、新しいCollectionを返します。

条件はコールバック関数で指定します。

例えば、偶数の数値だけを含む新しいCollectionを作成する場合は以下のようになります。

$collection = collect([1, 2, 3, 4, 5]);

$evenNumbers = $collection->filter(function ($item) {
    return $item % 2 === 0;
});

// $evenNumbersは[1 => 2, 3 => 4]を持つ新しいCollection

ここで注目してほしいのは、filterで抽出された要素のインデックスまでそのままである点です。

連番のCollectionを得るにはvaluesメソッドを使います。

$evenNumbers2 = $evenNumbers->values();

/*
    $evenNumbers2は[0 => 2, 1 => 4]を持つ新しいCollection
*/

where

whereメソッドは、key=>value形式のCollectionから、条件を満たす要素だけを持つ新しいCollectionを返します。

以下の例が、key=>value形式のCollectionです。

クエリビルダーの結果はこのようなCollectionです。

$users = collect([
    ['name' => 'サザエ', 'gender' => 'female', 'age' => 24],
    ['name' => '波平', 'gender' => 'male', 'age' => 54],
    ['name' => 'フネ', 'gender' => 'female', 'age' => 50],
    ['name' => 'マスオ', 'gender' => 'male', 'age' => 28],
]);

例えば、性別がfemaleのユーザーだけを含む新しいCollectionを作成する場合は以下のようになります。

$femaleUsers = $users->where('gender', 'female');

/*
$femaleUsers->toArray():
    [
        0 => ['name' => 'サザエ', gender='female', 'age' => 24],
        2 => ['name' => 'フネ', gender='female', 'age' => 50],
    ]
*/

オプションとして、 !==<などのオペレーターを指定することもできます。

例えば、年齢が30歳未満のユーザーだけを含む新しいCollectionを作成する場合は以下のようになります。

$youngUsers = $users->where('age', '<', '30');

/*
$youngUsers->toArray():
    [
        0 => ['name' => 'サザエ', gender='female', 'age' => 24],
        3 => ['name' => 'マスオ', gender='male', 'age' => 28],
    ]
*/

なお、ここでもfilterメソッドと同様にインデックスがそのままですが、valuesメソッドを使って連番にできます。

$youngUsers = $users->where('age', '<', '30')->values();

filterとwhereの違い

filterもwhereも条件を満たす要素を抽出して新しいCollectionを返すという点でよく似ていますが、使いどころが異なります。

違いを押さえておきましょう。

  • filterはクロージャーを渡せるので、より複雑な処理を書くことができる。
  • filterはkey=>value形式でなくても対応できる。
  • whereはkey=>value形式に限定されるが、その形式であれば記述量が少なくて済む。

メソッドを組み合わせて宣言的に書こう

Collectionはメソッドを続けて呼び、連続して操作を行うことができます。

これをメソッドチェーンといいます。

例えば、年齢が30歳未満の女性ユーザーだけを含む新しいCollectionを作成する場合は以下のようになります。

$selectedUsers = $users
                    ->where('gender', 'female')
                    ->where('age', '<', 30)
                    ->values();
/*
$selectedUser->toArray():
    [
        ['name' => 'サザエ', gender='female', 'age' => 24],
    ]
*/

このように、Collectionのメソッドを有効に組み合わせて、宣言的なコードを書くことを意識しましょう。

宣言的とは、何がしたいかが一目でわかるような書き方のことです。

上記の例では「genderがfemaleでageが30未満のuserがほしい」ことを簡潔に書いています。

シェアしてね〜🤞