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がほしい」ことを簡潔に書いています。