- カテゴリ: collection
- 対応バージョン: Laravel 11・12・PHP 8.2
- 名前空間 / FQCN / コマンド:
Illuminate\Support\Collection::chunk - 関連: chunkWhile / split / splitIn / forPage / Eloquent\Builder::chunk
- 変更履歴: ―
要点(TL;DR)
- コレクションをサイズごとに小分け(チャンク)する
collect([1,2,3,4,5])->chunk(2)- 罠: 巨大データを丸ごと読み込み→メモリ逼迫/DBの chunk と混同/キーは保持(必要なら
values()で詰め直す)
概要
chunk($size) は、元の Collection を指定件数ごとに区切り、「コレクションのコレクション」を返します。グリッド描画やバッチ処理の分割などで便利です。大量データは Eloquent\Builder::chunk() や LazyCollection と組み合わせてストリーミング処理に切り替えましょう。
構文 / シグネチャ
use Illuminate\Support\Collection;
public function Collection::chunk(int $size): Collection
- 引数
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| $size | int | ✅ | なし | 1 以上の分割サイズ。最後のチャンクは不足分を含む |
- 戻り値:
Collection<Collection<mixed>>(各要素は小分け後のコレクション) - 例外/副作用:
$size < 1で ValueError(内部でarray_chunk相当を使用)。副作用なし(非破壊)。
使用例
最小例
<?php
use Illuminate\Support\Facades\Route;
Route::get('/demo/chunk', function () {
$chunks = collect(['a' => 10, 'b' => 20, 'c' => 30, 'd' => 40, 'e' => 50])->chunk(2);
// キーは各チャンク内で保持される
return $chunks->map(fn ($c) => $c->all())->all();
});
// 出力例: [
// ['a' => 10, 'b' => 20],
// ['c' => 30, 'd' => 40],
// ['e' => 50],
// ]
実務例(通知を 100 件ごとにバッチ化)
use App\Models\User;
use Illuminate\Support\Facades\Bus;
$jobs = collect(User::query()->whereNotNull('email')->pluck('id'))
->chunk(100) // 100件ずつ分割(※全件pluckはメモリに乗る点に注意)
->map(fn ($ids) => new \App\Jobs\SendNotificationBatch($ids->all()));
Bus::batch($jobs)->dispatch();
大規模データは LazyCollection でストリーミング
use App\Models\User;
// メモリ節約: DB から逐次カーソル取得 → 100件ずつチャンク
User::cursor()
->chunk(100) // LazyCollection の chunk
->each(function ($chunk) {
// $chunk は通常の Collection。ここで処理やジョブ投入
dispatch(new \App\Jobs\SendNotificationBatch($chunk->pluck('id')->all()));
});
コレクション特性(collection ルール)
- チェーン可否: 可(
chunk()->map()->each()等) - 破壊的/非破壊: 非破壊(元コレクションは変更しない)
- キー保持: 保持する(各チャンク内で元キーを維持)
- LazyCollection 対応: 可(
cursor()->chunk()で低メモリ処理) - 計算量の目安: O(n)(n は要素数)
入出力対応(小さなサンプル)
| 入力 | chunk(3) の出力(概念) |
|---|---|
['a'=>1,'b'=>2,'c'=>3,'d'=>4] | [[a=>1,b=>2,c=>3],[d=>4]] |
[0=>1, 2=>2, 5=>3] | [[0=>1,2=>2,5=>3]](キーは保持) |
よくある落とし穴・注意
- DB の
chunk()と混同:Eloquent/Query\Builder::chunk($size, $callback)は逐次的に DB から取得。Collection::chunk()はすでにメモリ上のデータを分割。 - メモリ使用量:巨大配列をいきなり
collect()->chunk()すると負荷増。cursor()+LazyCollection::chunk()へ。 - キー詰め直し:UI の連番インデックスが必要なら、
$chunk->values()を併用。 - ネスト形状:戻りは「コレクションの配列」ではなく**「コレクションのコレクション」**。配列が欲しければ
->map->all()->all()。
代替・関連APIとの比較
chunkWhile(callable):条件が変わるまで同じチャンクに連結。内容ベースで区切りたいとき。split(int $number)/splitIn(int $number):分割数を先に決めて均等割り(端数調整あり)。forPage(int $page, int $perPage):特定ページだけ切り出し(単一ページ抽出)。Eloquent\Builder::chunk(int $size, callable $cb):DB から逐次取得してコールバック処理。超大規模データはこれ。
選定基準
- 「固定サイズで区切って全部回す」→
chunk($size) - 「条件の変化点で区切る」→
chunkWhile() - 「N 分割にしたい」→
split()/splitIn() - 「ページングの一部だけ」→
forPage() - 「DB 超大量データ」→
Eloquent::chunk()orcursor()+LazyCollection::chunk()
テスト例(Pest)
<?php
use Illuminate\Support\Collection;
it('splits collection with preserved keys', function () {
$chunks = collect(['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5])->chunk(2);
expect($chunks)->toHaveCount(3);
expect($chunks->first()->keys()->all())->toBe(['a','b']);
expect($chunks->last()->all())->toBe(['e' => 5]);
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 |
|---|---|---|
ValueError: ... length must be greater than 0 | $size が 0 以下 | chunk(1以上) を指定 |
| メモリ不足 / 非常に遅い | 全件を collect() してから chunk() | cursor()+LazyCollection::chunk() または Eloquent::chunk() を使用 |
| 想定と違うインデックス | キー保持仕様を失念 | 各チャンクで values() を呼び連番化 |
| 期待した配列形でない | ネストが Collection<Collection> | ->map->all()->all() で配列へ変換 |
参考リンク
- Laravel Docs — Collections: Chunk(公式): https://laravel.com/docs/11.x/collections#method-chunk
- Laravel Docs — Lazy Collections(公式): https://laravel.com/docs/11.x/collections#lazy-collections
- Laravel Docs — Database Chunking(公式): https://laravel.com/docs/11.x/eloquent#chunking-results
- PHP Manual —
array_chunk:https://www.php.net/array_chunk

