Laravel Collection完全ガイド|配列との違い・作成方法・頻出メソッド・メソッドチェーンを徹底解説

CollectionメソッドリファレンスLaravel入門基本文法・構文ガイド

Laravelでデータを扱う際、避けて通れないのが「コレクション(Collection)」です。データベースから取得したEloquentモデル群や、APIレスポンスの配列、フォーム入力データなどを直感的かつ安全に操作するための強力なツールであり、Laravelの大きな魅力の1つとなっています。

しかし、PHPを始めたばかりの方やLaravel初心者の方の中には、「普通のPHP配列と何が違うの?」「collect()で何ができるの?」「メソッドチェーンはどう書けばいい?」といった疑問を抱く方も多いのではないでしょうか。

本記事では、Laravel Collectionの基本概念や配列との違いから、collect()による作成方法、メソッドチェーンの仕組み、実務で毎日使う頻出メソッド一覧、Eloquent Collectionとの違い、現場で役立つ実践例やよくある落とし穴まで、実際にLaravel 11 / 12環境で動作確認したコードとともに徹底解説します。

  1. Laravel Collectionとは?配列(PHP Array)との違い
    1. PHPの標準配列とLaravel Collectionの比較
    2. コード比較:同じ処理を配列関数とCollectionで書く
  2. Collectionの作成方法とデータ変換
    1. 1. collect() ヘルパー関数(最も一般的)
    2. 2. Collection::make() と静的ファクトリ
    3. 3. 連番や繰り返し生成:range() と times()
    4. 4. 単一値や配列を安全に包む:wrap()
    5. 5. データベース(Eloquent・クエリビルダ)からの自動生成
    6. 6. Collectionを配列やJSONに変換して取り出す(all / toArray / toJson)
  3. メソッドチェーンの仕組みと書き方のコツ
    1. 不変性(イミュータブル)の基本ルール
    2. デバッグの極意:チェーンの途中で tap() や dump() を挟む
    3. モダンPHP(PHP 8.x)のアロー関数でスッキリ書く
  4. 【目的別】実務で頻出するCollectionメソッド完全ガイド
    1. 1. フィルタリング・抽出系メソッド
    2. 2. 変換・加工系メソッド
    3. 3. グループ化・分割系メソッド
    4. 4. 集計・判定系メソッド
    5. 5. ソート・集合演算系メソッド
    6. 6. 高階メッセージ(Higher Order Messages)による短縮記法
  5. Support Collection vs Eloquent Collectionの違い
    1. よくあるエラー:Support Collectionに find() を呼んでしまう
  6. 実務で役立つ実践ユースケース3選
    1. ユースケース1: ショッピングカートの合計金額と割引計算
    2. ユースケース2: 外部APIレスポンスの正規化とバリデーション
    3. ユースケース3: 部署・役職別のダッシュボード統計集計
  7. 初心者がつまずきやすい落とし穴と注意点
    1. 1. filter や where の後に values() を忘れて連想配列になる問題
    2. 2. 大量データでメモリが枯渇する(LazyCollection / cursorの活用)
    3. 3. Eloquentループ内でのCollectionリレーション呼び出し(N+1問題)
  8. よくある質問(FAQ)
    1. Q1. collect() と new Collection() の違いは?
    2. Q2. Collectionに自作の便利メソッドを追加できますか?
    3. Q3. PHPの標準配列関数と比べて速度面のオーバーヘッドはありますか?
  9. まとめ
  10. 関連記事

Laravel Collectionとは?配列(PHP Array)との違い

Laravel Collection(Illuminate\Support\Collection)とは、PHPの標準配列をオブジェクト指向的に便利に操作できるようにラップしたクラスです。公式ドキュメントでは「流れるようなインターフェース(Fluent Interface)」と表現されており、複数のデータ加工処理をチェーンのように連結して直感的に記述できます。

// 配列をコレクションに変換してフィルタと変換をチェーン実行
$collection = collect([1, 2, 3, 4, 5, 6]);

$result = $collection
    ->filter(fn (int $n) => $n % 2 === 0) // 偶数だけを抽出 [2, 4, 6]
    ->map(fn (int $n) => $n * 10)         // 10倍に変換 [20, 40, 60]
    ->values();                           // インデックスをリセット

$result->all(); // [20, 40, 60]

PHPの標準配列とLaravel Collectionの比較

PHP標準の配列関数(array_map, array_filter, array_values など)を使用する場合と、Laravel Collectionを使用する場合の違いを整理しました。

比較項目 PHP標準の配列(array) Laravel Collection
データ型 プリミティブな配列型 オブジェクト(Collectionクラス)
操作スタイル 関数に関数を入れ子にする、または都度変数に代入 オブジェクトのメソッドをメソッドチェーンで連結
引数の順序 関数ごとに順序がバラバラ(コールバック先行 or 配列先行) 一貫したAPI設計で迷わない
不変性(イミュータブル) 関数によって破壊的・非破壊的が混在 原則として元のインスタンスを変更せず新しいCollectionを返す
Eloquentとの連携 別途変換が必要 User::all()などの結果が最初からCollectionとして返る
エラー安全性 存在しないキー参照時にWarningやエラーになりやすい get()でデフォルト値指定など安全なメソッドが豊富

コード比較:同じ処理を配列関数とCollectionで書く

「ユーザー一覧からアクティブな人を抽出し、名前を大文字にして、名前の昇順で並び替える」処理を比較してみましょう。

// サンプルデータ
$users = [
    ['name' => 'tanaka', 'active' => true],
    ['name' => 'suzuki', 'active' => false],
    ['name' => 'sato',   'active' => true],
];

// 1. PHP標準の配列関数を使った場合(入れ子または中間変数が必要で可読性が低い)
$activeUsers = array_filter($users, fn ($u) => $u['active']);
$userNames = array_map(fn ($u) => strtoupper($u['name']), $activeUsers);
sort($userNames); // 破壊的ソート
// 結果: ['SATO', 'TANAKA']

// 2. Laravel Collectionを使った場合(処理の流れが上から下に流れて一目瞭然)
$result = collect($users)
    ->where('active', true)
    ->pluck('name')
    ->map(fn (string $name) => strtoupper($name))
    ->sort()
    ->values();
// 結果: ['SATO', 'TANAKA']

配列関数では「処理の順番」と「コードの記述順」が逆になったり、関数の引数順(array_map($callback, $array)array_filter($array, $callback))に悩まされたりしますが、Collectionを使えば左から右、上から下へと直感的にコードを組み立てられます。

Collectionの作成方法とデータ変換

Collectionインスタンスを作成する方法はいくつか用意されています。状況に応じて使い分けましょう。

1. collect() ヘルパー関数(最も一般的)

最も手軽で実務で頻出するのが、グローバルヘルパー関数 collect() です。配列や反復可能(Iterable)なオブジェクトを渡すだけでCollectionが生成されます。

// 空のコレクション
$empty = collect();

// 数値配列から生成
$numbers = collect([10, 20, 30]);

// 連想配列から生成
$user = collect([
    'id' => 1,
    'name' => '山田太郎',
    'email' => 'yamada@example.com',
]);

詳しい使い方はcollect — 配列/反復可能を Collection に変換するヘルパーをご覧ください。

2. Collection::make() と静的ファクトリ

クラスの静的メソッド Collection::make() を明示的に呼び出すことも可能です。

use Illuminate\Support\Collection;

$collection = Collection::make(['apple', 'banana', 'orange']);

3. 連番や繰り返し生成:range() と times()

テストデータ作成やループ処理用の連番コレクションをすばやく作成できるメソッドです。

use Illuminate\Support\Collection;

// 1から5までの連番コレクションを作成: [1, 2, 3, 4, 5]
$range = Collection::range(1, 5);

// 指定回数分コールバックを実行してコレクションを作成: [10, 20, 30]
$times = Collection::times(3, fn (int $n) => $n * 10);

関連記事:range — 連番のコレクションを生成する静的メソッドtimes — 指定回数ぶん要素を生成する

4. 単一値や配列を安全に包む:wrap()

渡された値がすでにCollectionであればそのまま返し、配列ならCollection化し、単一の値(文字列や数値)なら1要素のCollectionに包んで返します。引数の型が不確定なユーティリティ関数などで重宝します。

use Illuminate\Support\Collection;

Collection::wrap(['a', 'b']); // ['a', 'b'] の Collection
Collection::wrap('single');    // ['single'] の Collection
Collection::wrap(null);        // 空の Collection

関連記事:wrap — 単一値や配列をコレクションに包む

5. データベース(Eloquent・クエリビルダ)からの自動生成

Laravelでは、Eloquentモデルやクエリビルダで複数レコードを取得した際、結果が自動的にCollectionインスタンスとして返されます。

use App\Models\User;
use Illuminate\Support\Facades\DB;

// クエリビルダ: Illuminate\Support\Collection が返る
$posts = DB::table('posts')->where('status', 'published')->get();

// Eloquent: Illuminate\Database\Eloquent\Collection が返る
$users = User::where('active', true)->get();

6. Collectionを配列やJSONに変換して取り出す(all / toArray / toJson)

処理が終わったCollectionを通常のPHP配列やJSON文字列に戻したい場合は、以下のメソッドを使用します。

メソッド 戻り値の型 特徴
all() array 浅い変換。コレクション内のネストされたオブジェクトやモデルはそのまま維持される
toArray() array 深い(再帰的)変換。内部のCollectionやEloquentモデルもすべて純粋な配列に変換される
toJson() string JSON文字列にシリアライズして返す(APIレスポンス等)
$collection = collect([
    'user' => collect(['id' => 1, 'name' => '田中']),
]);

// all(): 内部のコレクションはオブジェクトのまま
$allResult = $collection->all();
// ['user' => Collection { ... }]

// toArray(): 内部のコレクションも配列に再帰変換
$arrayResult = $collection->toArray();
// ['user' => ['id' => 1, 'name' => '田中']]

関連記事:all — コレクションを生配列(array)に取り出す

メソッドチェーンの仕組みと書き方のコツ

Laravel Collectionの真価はメソッドチェーン(Method Chaining)にあります。各メソッドがどのような規則で動き、どう書くのがベストプラクティスなのかを押さえましょう。

不変性(イミュータブル)の基本ルール

Collectionの大部分のメソッドは、「元のコレクションを変更せず、処理結果を反映した新しいコレクションインスタンスを返す」という不変性(Immutability)を持っています。

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

// 新しいコレクションが返されるが、変数に代入していない
$original->map(fn ($n) => $n * 2);

// 元の $original は [1, 2, 3] のまま!
$original->all(); // [1, 2, 3]

// 正しい書き方: メソッドチェーンで繋ぐか、結果を再代入する
$doubled = $original->map(fn ($n) => $n * 2);
$doubled->all(); // [2, 4, 6]

※例外として、transform()push()pop()shift()put()forget() などの一部メソッドは元のインスタンス自体を書き換える破壊的メソッドです。

デバッグの極意:チェーンの途中で tap() や dump() を挟む

メソッドチェーンが長くなると、「どのステップでデータがどう変化したか」を確認したくなることがあります。その際に便利なのが dump()dd()tap() です。

$result = collect([10, 25, 30, 45, 50])
    ->filter(fn ($n) => $n >= 30)
    ->dump() // ここまでの状態 [30, 45, 50] をブラウザ/コンソールに出力して処理続行
    ->map(fn ($n) => $n * 2)
    ->tap(function ($collection) {
        // ログ出力などの副作用処理を挟む
        \Log::info('加工後データ件数: ' . $collection->count());
    })
    ->values();

関連記事:dump — コレクションを出力して処理を継続tap — コレクションに対する副作用を挟んで同じインスタンスを返す

モダンPHP(PHP 8.x)のアロー関数でスッキリ書く

PHP 7.4以降で導入された短縮無名関数(アロー関数 fn ($item) => expression)を使うと、function ($item) { return expression; } に比べてボイラープレートを大幅に削減できます。外側の変数も自動的にキャプチャされるため非常に相性が抜群です。

$taxRate = 1.10;

// アロー関数を使用すると $taxRate を use() なしで自然に参照可能
$prices = collect([1000, 2000, 3000])
    ->map(fn (int $price) => (int) round($price * $taxRate));

【目的別】実務で頻出するCollectionメソッド完全ガイド

Laravel Collectionには100種類以上のメソッドが用意されています。ここでは実務で特によく使う必須メソッドをカテゴリ別に紹介します。

1. フィルタリング・抽出系メソッド

メソッド 概要 解説記事リンク
filter() コールバックが true を返した要素だけを抽出(引数なしでfalsy除去) filterの使い方
reject() コールバックが true を返した要素を除外(filterの逆)
where() 指定キーが特定の値と一致する要素を抽出 whereの使い方
whereIn() 指定キーの値が配列内に含まれる要素を抽出 whereInの使い方
whereNotIn() 指定キーの値が配列内に含まれない要素を抽出 whereNotInの使い方
pluck() 指定キーの値だけを抜き出してフラットまたはキーペア配列を作成 pluckの使い方
first() / last() コレクションの先頭/末尾要素を取得(条件付き抽出も可能) lastの使い方
firstWhere() 指定キーと値に一致する最初の要素を直接取得
only() / except() 指定したキーのみを残す/除外する onlyの使い方
take() 先頭(または負の数で末尾)から指定件数を取り出す takeの使い方
$products = collect([
    ['id' => 1, 'name' => 'ノートPC', 'price' => 120000, 'in_stock' => true],
    ['id' => 2, 'name' => 'マウス',   'price' => 3000,   'in_stock' => true],
    ['id' => 3, 'name' => 'キーボード', 'price' => 8000,  'in_stock' => false],
]);

// 在庫ありの商品名一覧を取得: ['ノートPC', 'マウス']
$inStockNames = $products->where('in_stock', true)->pluck('name');

// 5000円以上の最初の商品を取得: ['id' => 1, 'name' => 'ノートPC', ...]
$firstExpensive = $products->first(fn ($p) => $p['price'] >= 5000);

2. 変換・加工系メソッド

メソッド 概要 解説記事リンク
map() 各要素に関数を適用し、戻り値で構成される新しいコレクションを返す mapの使い方
mapWithKeys() 各要素から [キー => 値] の連想配列を動的に組み立てる
flatMap() map処理を行い、結果の配列を1段階フラットにする
collapse() 配列の配列を1次元配列に結合する collapseの使い方
flatten() 何階層にもネストした多次元配列を完全フラットにする flattenの使い方
implode() 指定カラムや全要素を区切り文字で連結して文字列にする implodeの使い方
transform() 元のコレクション自身を破壊的に書き換えて要素を変換する transformの使い方
$users = collect([
    ['id' => 101, 'first_name' => '太郎', 'last_name' => '山田'],
    ['id' => 102, 'first_name' => '花子', 'last_name' => '佐藤'],
]);

// mapWithKeys で [id => フルネーム] の連想配列を作成
$userMap = $users->mapWithKeys(fn ($u) => [
    $u['id'] => "{$u['last_name']} {$u['first_name']}"
]);
// 結果: [101 => '山田 太郎', 102 => '佐藤 花子']

3. グループ化・分割系メソッド

メソッド 概要 解説記事リンク
groupBy() キーやコールバックの戻り値で要素をグループ化する groupByの使い方
partition() 条件を満たすものと満たさないものの2つのコレクションに分割
chunk() コレクションを指定した件数ごとの小グループに分割 chunkの使い方
forPage() ページ番号と1ページあたり件数を指定して一部を切り出し forPageの使い方
$orders = collect([
    ['id' => 1, 'category' => 'book', 'amount' => 1500],
    ['id' => 2, 'category' => 'food', 'amount' => 800],
    ['id' => 3, 'category' => 'book', 'amount' => 2200],
]);

// カテゴリごとにグループ化
$grouped = $orders->groupBy('category');
// 'book' => [order 1, order 3], 'food' => [order 2]

// partition: 1000円以上と未満に一括分割
[$expensive, $cheap] = $orders->partition(fn ($o) => $o['amount'] >= 1000);

4. 集計・判定系メソッド

メソッド 概要 解説記事リンク
count() コレクションの要素数を返す countの使い方
countBy() 値ごとの出現回数を集計する countByの使い方
sum() / avg() 指定カラムや全要素の合計値・平均値を計算 avgの使い方
contains() コレクションに特定の値や条件を満たす要素が含まれるか判定(true/false) containsの使い方
has() 指定したキーが存在するか判定 hasの使い方
isEmpty() / isNotEmpty() コレクションが空であるか/空でないかを判定 isEmptyの使い方
every() すべての要素が指定した条件を満たすかを判定 everyの使い方
$scores = collect([80, 95, 70, 85, 90]);

$scores->avg(); // 84
$scores->sum(); // 420
$scores->every(fn ($s) => $s >= 60); // true(全員合格点以上)

$roles = collect(['admin', 'editor', 'editor', 'subscriber']);
$roles->countBy(); // ['admin' => 1, 'editor' => 2, 'subscriber' => 1]

5. ソート・集合演算系メソッド

メソッド 概要 解説記事リンク
sortBy() / sortByDesc() キーやコールバックで昇順/降順にソート(非破壊) sortByの使い方
sort() 値でシンプルに並び替える(キー保持) sortの使い方
values() 要素のキーを 0, 1, 2... の連番にリセットする valuesの使い方
unique() 重複する要素を取り除く(キー指定も可能) uniqueの使い方
merge() / union() コレクション同士や配列を結合(文字列キー上書き vs 左優先結合) mergeの使い方unionの使い方
diff() / intersect() 差分要素の抽出/共通要素の抽出 diffの使い方intersectの使い方

6. 高階メッセージ(Higher Order Messages)による短縮記法

コレクションには「高階メッセージ」という構文糖衣(シンタックスシュガー)があり、クロージャを書く代わりにプロパティやメソッド名を直接チェーンできます。

$users = User::all();

// 通常の書き方
$names = $users->map(fn ($user) => $user->name);
$sum = $users->sum(fn ($user) => $user->points);

// 高階メッセージを使った書き方(驚くほど簡潔!)
$names = $users->map->name;
$sum = $users->sum->points;

// 各モデルのメソッドを直接実行することも可能
$users->each->sendWelcomeNotification();

Support Collection vs Eloquent Collectionの違い

Laravelには実は2種類の代表的なCollectionが存在します。

  1. Base Collection(Illuminate\Support\Collectioncollect()DB::table()->get() で生成される汎用コレクション
  2. Eloquent Collection(Illuminate\Database\Eloquent\CollectionUser::all() などEloquent経由で生成されるモデル専用コレクション
比較項目 Support Collection Eloquent Collection
クラス Illuminate\Support\Collection Illuminate\Database\Eloquent\Collection
継承関係 親クラス(独立) Support Collectionを継承(サブクラス)
内部要素 配列、プリミティブ値、任意のオブジェクト Eloquent Modelインスタンス
基本メソッド map, filter, pluck, sortBy などすべて利用可能 Support Collectionの全メソッドをそのまま利用可能
固有メソッド なし find(), load(), loadMissing(), modelKeys(), makeVisible(), fresh() など

よくあるエラー:Support Collectionに find() を呼んでしまう

find() メソッドは Eloquent Collection固有のメソッド(主キーIDでモデルを探すメソッド)です。通常の collect() で作成したコレクションに対して $collection->find($id) を呼ぶとエラーになります。

$items = collect([
    ['id' => 1, 'name' => '商品A'],
    ['id' => 2, 'name' => '商品B'],
]);

// エラー発生: Call to undefined method Illuminate\Support\Collection::find()
// $items->find(1);

// 正しい書き方: firstWhere または where を使う
$item = $items->firstWhere('id', 1);

関連記事:Laravel Collectionのfindメソッドの使い方|「undefined method」エラーの原因と対処

実務で役立つ実践ユースケース3選

現場の開発現場でCollectionがどのように活躍するのか、実践的なコード例を3つ紹介します。

ユースケース1: ショッピングカートの合計金額と割引計算

// app/Services/CartService.php
namespace App\Services;

class CartService
{
    public function calculateTotal(array $cartItems, float $couponDiscountRate = 0.0): array
    {
        $items = collect($cartItems);

        // 1. 有効な商品だけに絞り込み、小計を計算
        $processedItems = $items
            ->where('quantity', '>', 0)
            ->map(function (array $item) {
                $subtotal = $item['price'] * $item['quantity'];
                return array_merge($item, ['subtotal' => $subtotal]);
            });

        // 2. カート全体の小計を合算
        $subtotalSum = $processedItems->sum('subtotal');

        // 3. クーポン割引の適用
        $discountAmount = (int) round($subtotalSum * $couponDiscountRate);
        $totalAfterDiscount = max(0, $subtotalSum - $discountAmount);

        // 4. 送料無料判定(5,000円以上で無料)
        $shippingFee = ($totalAfterDiscount >= 5000 || $totalAfterDiscount === 0) ? 0 : 550;

        return [
            'items' => $processedItems->values()->all(),
            'item_count' => $processedItems->sum('quantity'),
            'subtotal' => $subtotalSum,
            'discount' => $discountAmount,
            'shipping_fee' => $shippingFee,
            'grand_total' => $totalAfterDiscount + $shippingFee,
        ];
    }
}

ユースケース2: 外部APIレスポンスの正規化とバリデーション

// app/Services/WeatherApiService.php
namespace App\Services;

use Illuminate\Support\Collection;

class WeatherApiService
{
    public function formatWeeklyForecast(array $rawApiResponse): Collection
    {
        return collect($rawApiResponse['forecasts'] ?? [])
            ->filter(fn ($day) => isset($day['temperature'], $day['date'])) // 欠損データ除外
            ->map(fn ($day) => [
                'date' => $day['date'],
                'weather' => $day['telop'],
                'temp_max' => (int) ($day['temperature']['max']['celsius'] ?? 0),
                'temp_min' => (int) ($day['temperature']['min']['celsius'] ?? 0),
                'rain_chance' => $day['chanceOfRain']['T12_18'] ?? '0%',
            ])
            ->sortBy('date')
            ->values();
    }
}

ユースケース3: 部署・役職別のダッシュボード統計集計

// コントローラー等での集計処理
$employees = collect([
    ['id' => 1, 'name' => '田中', 'dept' => '開発部', 'salary' => 500000, 'is_leader' => true],
    ['id' => 2, 'name' => '佐藤', 'dept' => '開発部', 'salary' => 380000, 'is_leader' => false],
    ['id' => 3, 'name' => '鈴木', 'dept' => '営業部', 'salary' => 450000, 'is_leader' => true],
    ['id' => 4, 'name' => '高橋', 'dept' => '営業部', 'salary' => 320000, 'is_leader' => false],
    ['id' => 5, 'name' => '伊藤', 'dept' => '営業部', 'salary' => 350000, 'is_leader' => false],
]);

// 部署ごとの人数と平均給与を集計
$deptStats = $employees
    ->groupBy('dept')
    ->map(fn (Collection $members) => [
        'member_count' => $members->count(),
        'leader_name'  => $members->firstWhere('is_leader', true)['name'] ?? '未定',
        'avg_salary'   => (int) round($members->avg('salary')),
        'total_salary' => $members->sum('salary'),
    ]);

// 結果:
// [
//     '開発部' => ['member_count' => 2, 'leader_name' => '田中', 'avg_salary' => 440000, 'total_salary' => 880000],
//     '営業部' => ['member_count' => 3, 'leader_name' => '鈴木', 'avg_salary' => 373333, 'total_salary' => 1120000],
// ]

初心者がつまずきやすい落とし穴と注意点

1. filter や where の後に values() を忘れて連想配列になる問題

filter()where()元のキー(インデックス番号)をそのまま維持します。そのため、先頭以外の要素が抽出された場合、インデックスが [1 => 'b', 3 => 'd'] のようになります。

$items = collect(['a', 'b', 'c', 'd']);

$filtered = $items->filter(fn ($item) => in_array($item, ['b', 'd']));

// インデックスが 0 から始まらない!
$filtered->all(); // [1 => 'b', 3 => 'd']

// これをそのまま json_encode すると、JSON配列 "[]" ではなく JSONオブジェクト "{}" に化けてしまう!
json_encode($filtered); // '{"1":"b","3":"d"}'

// 対策: values() をチェーンして 0, 1, 2... にリセットする
$fixed = $filtered->values();
json_encode($fixed); // '["b","d"]'

Vue.jsやReactなどのフロントエンドにAPI経由で配列を返す際、values() を忘れて「配列だと思ったらオブジェクトが返ってきた」というバグは頻出です。必ず values() を呼び出しましょう。

関連記事:values — 連番キーで再構築する

2. 大量データでメモリが枯渇する(LazyCollection / cursorの活用)

データベースに数十万件〜数百万件のレコードがある場合、User::all() で全件をCollectionに読み込むと、PHPの memory_limit(メモリ上限)に達してFatal Errorになります。

// NG: 100万件のモデルを一気にメモリに展開してメモリ枯渇
// $users = User::all();

// OK: cursor() を使って LazyCollection(遅延コレクション)として1件ずつ処理
use App\Models\User;

User::where('status', 'active')
    ->cursor() // Illuminate\Support\LazyCollection を返す
    ->filter(fn (User $user) => $user->needsRenewal())
    ->each(function (User $user) {
        $user->sendRenewalNotice();
    });

LazyCollection はPHPのジェネレータ(yield)を利用しており、100万件あっても数MBのメモリだけでストリーム処理できます。

3. Eloquentループ内でのCollectionリレーション呼び出し(N+1問題)

// NG: N+1問題の発生(ループごとにSQLが走る)
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->comments->count(); // コメント取得クエリが毎回発行
}

// OK: Eager Loading(with)で事前にまとめてロードしておく
$posts = Post::with('comments')->get();
foreach ($posts as $post) {
    echo $post->comments->count(); // メモリ上のCollectionをカウントするため追加SQLなし
}

よくある質問(FAQ)

Q1. collect() と new Collection() の違いは?

どちらも内部的には new Collection($items) を生成しているため、動作上の違いはありません。ただし、ヘルパー関数の collect() を使う方が use Illuminate\Support\Collection; のインポート宣言が不要で、コードも短く書けるため、Laravelの公式ドキュメントおよび実務では collect() が推奨されています。

Q2. Collectionに自作の便利メソッドを追加できますか?

はい、Laravel Collectionは Macro(マクロ) に対応しています。AppServiceProviderboot() メソッド等で Collection::macro() を定義することで、プロジェクト全体で使える独自メソッドを追加できます。

// app/Providers/AppServiceProvider.php
namespace App\Providers;

use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // 文字列要素をすべて大文字にするマクロ 'toUpper' を定義
        Collection::macro('toUpper', function () {
            return $this->map(fn ($value) => is_string($value) ? strtoupper($value) : $value);
        });
    }
}

// 使用例
collect(['apple', 'banana'])->toUpper(); // ['APPLE', 'BANANA']

Q3. PHPの標準配列関数と比べて速度面のオーバーヘッドはありますか?

Collectionはオブジェクトの生成やメソッド呼び出し、クロージャの実行を伴うため、純粋なPHPのプリミティブ配列操作と比べるとわずかなオーバーヘッドが存在します。しかし、数千件〜数万件程度の通常のWebアプリケーション処理においてはミリ秒未満の差であり、可読性・保守性・安全性の向上がもたらすメリットの方が圧倒的に大きいです。極限のミリ秒単位のパフォーマンスが求められるバッチ処理のループ内を除き、基本的にはCollectionを採用するのがLaravel開発のベストプラクティスです。

まとめ

Laravelの Collection(コレクション) は、PHPの配列操作を劇的に直感的・安全・高機能に変えてくれる必須機能です。

  • 配列との違い:関数入れ子の煩雑さから解放され、読みやすく保守しやすいメソッドチェーンで処理を連結できる。
  • 作成と変換:手動作成は collect()、DB結果は自動的にCollection化。配列への復元は all()toArray() を使う。
  • 不変性:原則として元データを壊さず新しいインスタンスを返すため安全(破壊的メソッドとの違いに注意)。
  • インデックスのリセットfilter()where() を使った後は、フロントエンドでのJSON配列化を防ぐために values() を忘れない。
  • Eloquent Collection:Support Collectionを継承しており、find()load() などのモデル特有メソッドが追加されている。

まずは基本の mapfilterpluckwheregroupBy から使い始めて、Laravel開発の生産性とコードの見通しをグッと高めていきましょう!

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする

コメント