メシのタネ

めしのたねになるIT情報配信サイト


Laravel Collection入門: mapとeachの違い、ちゃんと説明できますか?


  1. Laravel
  2. Laravel Collection入門: mapとeachの違い、ちゃんと説明できますか?

その map()、ちゃんと使えてますか?

LaravelでControllerのレスポンスを整形していると、
いつの間にか map()filter()pluck() など、Collectionメソッドを使うようになります。

でも、こんな違和感がよぎったことはありませんか?

  • map()each()、なんとなく使い分けてるけど……違いって何?
  • filter() のあとに values() つけるけど、これ必要なの?
  • 結局、Collectionって配列と何がどう違うんだっけ?

Laravel Collectionは便利です。書くのも短くなるし、チェーンで読める。
でもその“便利さ”に任せて使っていると、ある日コードがよくわからない状態で動いていたり、
意図しない動作にハマったりすることがあります。

この記事では、Laravel Collectionを「雰囲気で書いてる」状態から、
「意図して使う」状態にレベルアップすることを目指します。

特に、タイトルにもある map()each()
この2つ、ぱっと見は似てるけど、考え方も目的も真逆です。

似ているからこそ、よく使うからこそ、きちんと使い分けられるようにする。
そのための、“わかってるつもり”を脱出する入門書として書きました。

本記事のゴール

  • Laravel Collectionの「考え方のベース」を理解する
  • よく使うメソッドの“使いどころ”を正しく見極められるようになる
  • 実務で書くCollectionコードが、読みやすく・壊れにくくなる
たねまる

「Collectionって、“何ができるか”じゃなくて、“どう使い分けるか”が肝なんだよね〜」

目次

🧱 Collectionとは何か?

LaravelのCollectionは、PHPの配列をラップしたイテラブルなオブジェクトです。
でも、それだけ聞くと「要するに便利な配列のことね」と思って終わりがちです。

でも本当は、CollectionにはLaravelの思想──
つまり、「処理の意図をコードに乗せる」「状態を変えずに変換する」という考え方が色濃く出ています。

Collectionは“配列のラッパー”であり“データ処理のフローを表す道具”

たとえば、ただの配列に対してこんな処理をしたいとき:

$users = [
    ['name' => 'Alice', 'age' => 25],
    ['name' => 'Bob', 'age' => 32],
    ['name' => 'Charlie', 'age' => 28],
];

// 30歳未満のユーザー名を取り出したい

配列でやるとこう:

$result = [];
foreach ($users as $user) {
    if ($user['age'] < 30) {
        $result[] = $user['name'];
    }
}

Collectionでやるとこう:

$names = collect($users)
    ->filter(fn($user) => $user['age'] < 30)
    ->pluck('name')
    ->values();

「フィルタして → nameを取り出して → 配列化する」
この人間の思考の順序がコードになります。

LaravelでどうやってCollectionが生まれるか?

Eloquentでデータを取ったときも、Collectionが使われています:

$users = User::where('active', true)->get(); 

この場合、中身は User モデルのインスタンスで、map(), filter(), pluck() などのメソッドが使えます。

一方、自分で配列から Collection を作るには collect() を使います:

collect(['a', 'b', 'c']); 
// => Illuminate\Support\Collection

この collect() は Laravel のグローバルヘルパ関数で、内部的には new Collection() しています。

🧠 補足:クエリビルダーからの get() は普通の Collection(中身は stdClass)

Eloquentモデルではなく、クエリビルダーを使うと戻り値の中身が変わります:

$rows = DB::table('users')->where('active', true)->get(); 
// => Illuminate\Support\Collection(中身は stdClass)

アクセス方法の違い:

$rows->first()->name; // OK(stdClass)
$rows->first()['name']; // エラー(配列じゃない)
ビルダー戻り値の型中身
EloquentIlluminate\Database\Eloquent\Collectionモデルのインスタンス (User, etc.)
クエリビルダーIlluminate\Support\CollectionstdClass

Collectionは「状態を持たない流れ」を書くための道具

map()filter() などのメソッドは、元のデータを直接変えずに、新しい Collection を返します

$updated = $original->map(...); // 元の $original はそのまま

↑の何が嬉しいの?

✅ 1. データの“持ち回し”がしやすくなる

たとえば、同じデータを使って

  • 一方では絞り込みだけしたい
  • もう一方ではソート+整形したい

みたいな処理をするとき、元のデータが書き換わらないことで、何度でも再利用できるのが便利です。

$filtered = $original->filter(...);
$summary = $original->map(...)->groupBy(...);

$original はどちらの処理にも使えるし、処理ごとに変数を分けて書くことができます。

✅ 2. 意図しない“上書き”や“影響の連鎖”が起きにくいたいなバグが起きにくい

配列で値を操作していると、どこで変えたか分かりづらくなることってありませんか?

たとえば、複数の関数や処理の中で同じ $users 配列を使い回してるうちに、
あれ?この時点でもう年齢加算されてた…」みたいな状態になってバグに気づく、みたいなこと。

$users = getUsers(); // 最初の配列

$updated = $users;
foreach ($updated as &$user) {
    $user['age'] += 1; // ここで加算
}

// 後の処理でも $users を使おうとしたら、年齢が変わってる

Collectionを使っていると、こういった「いつの間にか変わってる問題」を避けやすくなります。
なぜなら、map() などのメソッドは常に新しいCollectionを返すだけだからです。

$updated = $users->map(function ($user) {
    $user['age'] += 1;
    return $user;
});

// 元の $users はそのまま

🔑 「あとでまた使いたいデータが、勝手に変わってる…」という事故を防げる。
変換結果を“新しく作る仕組みを利用することで、安全に運用できます。

mapとeachの違い、ちゃんと使い分けできてる?

LaravelでEloquentのデータを扱っていると、get()した結果がCollectionになっていることに気づく人は多いはずです。
最初は first()count()pluck() あたりから自然と使い始めることが多いと思います。

でも開発に慣れてくると、「リストを加工したい」「値を変換したい」といった場面が出てきて、
そこで登場するのが map()each() です。

この2つ、「なんとなく雰囲気で使ってる」人も多いと思いますが、本質はまったく違うものです。

この章では、mapとeachの違いを明確に整理し、使い分けの基準やよくあるミスを見ていきます。

map():値を「変換」するためのメソッド

$users->map(function ($user) {
    return [
        'name' => strtoupper($user['name']),
        'age' => $user['age'] + 1,
    ];
});
  • 各要素を変換し、新しいCollectionを返す
  • 元のデータは変わらない(非破壊的)
  • return が必須。これがないと意味がない
  • 「このリストをこう変えたい」と明示できるのが強み

❌ よくあるミス:

$users->map(function ($user) {
    $user['is_admin'] = true;
});
// => [null, null, ...] が返る

変換のつもりで return を書かないと、全部 null になる。
「なんかうまく動いてると思ったらnull地獄だった」というバグ、たぶん人類全員一度はやる。

たねまる

ぼくもreturn書き忘れて、nullにしちゃったことあるよ〜。

each():値に「処理」を加えるためのメソッド(変換はしない)

$users->each(function ($user) {
    Log::info("User ID: {$user['id']}");
});
  • 各要素に対して処理だけ行う
  • 戻り値は元のCollectionのまま
  • return は書いても無視される
  • 副作用(ログ出力・DB書き込みなど)を起こすための道具

⚠️ 注意点:eachで変換はできない

$users->each(function ($user) {
    $user['is_admin'] = true;
});

これ、やった気になるけど実際は何も変わってない
配列は値渡しなので、$user はローカルコピーにすぎません。
(オブジェクトなら変わるけど、それでも意図が読みづらいコードになる)

💀 どうしてもeachで配列をいじりたいなら:

$users->each(function (&$user) {
    $user['is_admin'] = true;
});

↑参照渡し(&)を使えばいじれるけど、🧙‍♀️黒魔術🧙‍♀️ 途端にコードが気持ち悪くなる
「意図はmap、実装はeach(&)」みたいなコードは最悪。読む人をバグらせる。

たねまる

eachで変換しようとしてたら、気づいたら副作用おばけになってたこと、あるよね〜

🧠 mapとeachの違い、こう覚えると便利

比較項目map()each()
目的値の変換値の処理(副作用)
戻り値新しいCollection元のCollection
returnの扱い必要(これが結果になる)無視される
主な用途整形・加工・変換処理ログ出力、通知送信、DB保存など
副作用できるけど避けたい主目的が副作用
スタイル関数型っぽい命令的処理

🙋‍♀️ じゃあどう使い分けるの?

  • 新しいリストがほしいとき → map()
    • 例:ユーザー名だけ取り出す、値を整形する、変換した配列を返したい
  • 処理だけしたいとき → each()
    • 例:ログ出す、通知送る、何かを保存する、でもリスト自体はいじらない
  • 「変えたいのにeach使ってる」やつ → 悪いコード
    • 例:副作用と変換がごちゃ混ぜ、誰にも読まれない未来のレガシーコード製造中

🧠 補足:アロー関数(fn)の書き方と挙動

Laravelの記事やドキュメントでよく見かけるこの書き方:

$users->map(fn($user) => $user->name);

これは、PHP 7.4以降で使えるようになったアロー関数(arrow function)です。

✅ 特徴

  • fn($x) => 式 の1行構文で書ける
  • return を書かなくていい(暗黙のreturn)
  • 外側のスコープを自動でキャプチャ(use がいらない)
  • 複数行の処理は書けない(あくまで1行専用)
// 普通のクロージャ
$users->map(function ($user) {
    return $user->name;
});

// アロー関数で短く書く
$users->map(fn($user) => $user->name);

参考 → PHP公式マニュアル(Arrow Functions)

Arrow functions were introduced in PHP 7.4 as a more concise syntax for anonymous functions…

たねまる

アロー関数って現場では使ってるけど、本当にそういうのか、中の人は今日知ったんだって〜。
fn って書くと、なんだか賢くなった気がするよね〜。中身は同じなのに〜。

💡 まとめ:mapとeachは性格が真逆

LaravelのCollectionは、mapとeachを使い分けること
「意図が伝わるコード」になっていきます。

  • mapで変換することで、状態を持たない設計ができる
  • eachで処理を明確に分離することで、読んだ人が安心できるコードになる

「書いたコードに意味を乗せる」ために、この2つはぜひ明確に使い分けていきましょう。

実務でよく使う「美しいCollection」例3つ

LaravelのCollectionは、ループで書く処理を、短く・意図的に・再利用可能に書けるのが強みです。

ここでは、実務でありがちなデータ加工のパターンを3つ紹介します。

✅ パターン①:カテゴリ別に商品をグループ → 整形してJSONへ

$products = collect([
    ['name' => 'iPhone', 'category' => 'スマホ'],
    ['name' => 'Galaxy', 'category' => 'スマホ'],
    ['name' => 'MacBook', 'category' => 'PC'],
]);

$grouped = $products
    ->groupBy('category')
    ->map(function ($items, $category) {
        return [
            'category' => $category,
            'products' => $items->pluck('name')->values(),
        ];
    })
    ->values();

return response()->json($grouped)

👀 出力例:

[
    {
        "category": "スマホ",
        "products": ["iPhone", "Galaxy"]
    },
    {
        "category": "PC",
        "products": ["MacBook"]
    }
]

📌 ポイント:

  • groupBy で分類
  • map で整形(副作用なし!)
  • pluck → values で美しく並べ直し

✅ パターン②:条件でフィルタ → ソート → 数値変換して合計

$total = $orders
    ->filter(fn($order) => $order->status === 'completed')
    ->sortBy('completed_at')
    ->map(fn($order) => $order->total_price)
    ->sum();

📌 ポイント:

  • 条件でフィルタ → filter()
  • 並び順制御 → sortBy()
  • 欲しい値だけ抜き出し → map()
  • 最後に合計 → sum()

読み下すだけで処理の流れが見える。目にやさしい数値処理。

✅ パターン③:ログ記録しながら値を集計(map + tap)

$totals = $users->map(function ($user) {
    return tap([
        'name' => $user->name,
        'orders_total' => $user->orders->sum('total_price'),
    ], function ($summary) use ($user) {
        Log::info("Processed user {$user->id}", $summary);
    });
});

📌 ポイント:

  • map()で変換
  • tap()で副作用(ログ出力)を副流的に添える
  • 「データ変換」と「処理」をきれいに分ける書き方
たねまる

tapは容易に使うとれびゅあー?がまゆをひそめるらしいから、あんまり詳しく書かないことにしたんだって。ケチだね〜。

✨ まとめ:Collectionは「意図の見える処理」を書く道具

LaravelのCollectionは、ただ便利なだけじゃない。
「このデータをどう扱いたいのか?」をコードに直接刻み込める設計になってます。

  • ループでバラバラに書くより、流れで見せる
  • 変換はmap、副作用はeach
  • わかりやすさと再利用性を両立できる

Collectionを使うと、「どう処理するか」ではなく「何をしたいか」を表現できます。
意図が伝わるコードは、実装も保守も、ちょっとだけやさしくなる。

LaravelのCollectionは、そういう「書き味」を持った道具です。

たねまる

今日もいっぱい勉強したね〜。文字数7800文字。おなかいっぱーい。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.

若い頃、「仕事中にハマったこと」や「誰かに共有したい技術的な気づき」をアウトプットしたくてブログを始めましたが、勢い任せでよく分からない記事を大量生産し、あえなく飽きて終了。

改めて今、キャリア15年分の経験や知識が、これからITエンジニアを目指す方や、同じような課題で悩んでいる現役エンジニアの「メシのタネ」になるような記事を残したいと思っています。
※過去の記事は見ると精神が崩壊するため、そっとしておいてください。

🛠 経歴という名の珍道中:
文系Fラン → 広告営業 → Web営業 → 通信営業 → Web進行 → 出版 → Web媒体運用 → ソフトウェアハウス → SES → フリーランス

専門教育も受けず、転職歴も多数。履歴書はまるで時系列の事故記録のようですが、試行錯誤を重ね、なんとかエンジニアとして食べています。

このブログでは、そんな「履歴書クラッシャー型エンジニア」が送る、
名古屋一敷居の低い、実務に役立つ技術ブログを目指します。

Laravel
Laravel Collection入門: mapとeachの違い、ちゃんと説明できますか?New!!
Laravel
Eloquentのリレーション徹底解説New!!
Laravel
Eloquentは知ってる。でも“理解してる”って言えるのか?New!!
Laravel
FormRequestのポテンシャル、半分も出せてない説New!!
Laravel
Laravel Controllerの“万能感”、そこに幸せはあるのかい?New!!
API
RESTってつまり何?Webエンジニアが悩まないためのAPI設計入門