- カテゴリ: collection
- 掲載バージョン: Laravel 12・PHP 8.4
- 名前空間 / FQCN / コマンド:
Illuminate\Support\Collection::each - 関連: map / transform / tap / eachSpread / LazyCollection
- 変更履歴: 特記事項なし(コールバックがstrictに
falseを返すと反復停止)
要点(TL;DR)
- 各要素に対して処理(ログ出力・集計・API呼び出しなどの副作用)を実行する
collect($xs)->each(fn ($v, $k) => Log::info('v', compact('v','k')));- 罠:
false(厳密比較)以外の戻り値では停止しない/LazyCollectionは消費される/変換はしない(結果は元コレクション)
概要
each はコレクションの各要素に対し副作用を実行するためのメソッドです。返り値は同じコレクションインスタンスなのでチェーンが可能です。コールバックが厳密に false を返すと早期終了します。要素の変換が目的なら map / transform を使います。
構文 / シグネチャ
/**
* @template TKey of array-key
* @template TItem
* @param callable(TItem, TKey): (mixed|false|void) $callback
* @return static // 元のコレクションを返す
*/
public function each(callable $callback);
- 引数(表) 引数 型 必須 既定値 説明
$callback`callable(mixed $item, mixed $key): mixed false void` ✅ - 戻り値:
static(呼び出し元のコレクション) - 例外/副作用:コールバック内での例外はそのまま伝播。ファイル・DB・HTTPなどの副作用はコールバック次第。LazyCollection では反復によりストリームを消費。
使用例
最小例
use Illuminate\Support\Collection;
collect(['a' => 10, 'b' => 20, 'c' => 30])
->each(function ($value, $key) {
echo "{$key}: {$value}\n";
if ($value === 20) {
return false; // 'b' で停止(strict false)
}
});
実務例(通知・ログ・早期停止)
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
$orders = DB::table('orders')
->where('status', 'pending')
->orderBy('id')
->limit(1000)
->get(); // Collection<StdClass>
$orders->each(function ($order) {
try {
// 例:外部APIへ通知、またはキュー投入
Log::info('Notify order', ['id' => $order->id]);
// 条件により早期停止(厳密に false を返す)
if ($order->priority === 'urgent') {
return false;
}
} catch (\Throwable $e) {
Log::error('Notify failed', ['id' => $order->id, 'e' => $e->getMessage()]);
// 失敗しても反復は続けたい場合は false を返さない
}
});
よくある落とし穴・注意
- 変換はしない:
eachは要素を変えません。変換結果が必要ならmap(非破壊)かtransform(破壊的)を使う。 - 早期停止は
=== false:0や''、nullでは停止しない。止めたいときは必ずreturn false;。 - LazyCollection は消費:
LazyCollection::each()はストリームを読み切る(または停止条件まで)。2回目の反復はできない前提で設計する。 - 計算量:O(n)。重いI/O を各要素で実行するならバッチングやキューを検討。
代替・関連APIとの比較
- map:変換して新しいコレクションを返す。副作用より結果が目的ならこちら。
- transform:破壊的に要素を置き換える(同じインスタンスを書き換え)。ミュータブル前提の場面で。
- tap:コレクション全体を一度コールバックに渡す(各要素ではない)。デバッグやロギングに。
- eachSpread:各要素が配列/タプルのとき、引数展開してコールバックに渡す。
- PHP
foreach:フレームワーク非依存。**停止条件の明示(break)**が必要。チェーンしない。
テスト例(Pest)
use Illuminate\Support\Collection;
it('stops when callback returns strict false and does not mutate items', function () {
$log = [];
$c = collect([1, 2, 3]);
$returned = $c->each(function ($v) use (&$log) {
$log[] = $v;
if ($v === 2) {
return false; // strict false -> stop
}
});
expect($returned)->toBe($c); // 同一インスタンス
expect($log)->toBe([1, 2]); // 2で停止
expect($c->all())->toBe([1, 2, 3]); // 非破壊
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 |
|---|---|---|
| 停止しない | return null; や 0 を返している | **return false;(厳密)**に修正 |
2回目の each で何も起きない | LazyCollection を既に消費 | 一度きりの前提で設計/必要なら通常の Collection に変換してから処理 |
| 想定外に重い/タイムアウト | 各要素で外部I/Oを直列実行 | キュー投入・chunk・バッチAPI・レート制御を導入 |
| 変換結果が反映されない | each は非変換メソッド | map / transform を使用 |
コレクション特性(カテゴリ規約)
- チェーン可否:可(元インスタンスを返す)
- 破壊的/非破壊:非破壊
- キー保持:保持(処理対象の走査のみ)
- LazyCollection:対応。消費に注意
- 計算量の目安:O(n)
入出力対応表(小サンプル)
| 入力(例) | コールバック | 出力 | 備考 |
|---|---|---|---|
collect(['a'=>1,'b'=>2]) | ログ出力のみ | 同じコレクション | 副作用のみ |
collect([10,20,30]) | if ($v===20) return false; | 同じ | 20 で停止 |
参考リンク
- Laravel公式ドキュメント:Collections — each
https://laravel.com/docs/12.x/collections#method-each - Laravel公式ドキュメント:Collections — map / transform
https://laravel.com/docs/12.x/collections#method-map
https://laravel.com/docs/12.x/collections#method-transform - Laravel公式ドキュメント:Collections — eachSpread / tap
https://laravel.com/docs/12.x/collections#method-eachspread
https://laravel.com/docs/12.x/helpers#method-tap - Laravel公式ドキュメント:Lazy Collections
https://laravel.com/docs/12.x/collections#lazy-collections

