Collection::flatMap
Maps each item through a callback and collapses the results by exactly one level.
Collection::flatMap(callable $callback): staticParameters
| Parameter | Type | Description |
|---|---|---|
$callback | callable(TValue, TKey): (\Illuminate\Support\Collection|array) | Invoked with the item value first and its key second. Return an array or a collection; each of its elements becomes a separate item in the result. |
Return value
staticA new collection built by mapping every item and then collapsing the result a single level, so arrays and collections returned by the callback are merged into the output.
flatMap is map followed by collapse. The callback returns an array or collection for each item, and instead of nesting those results the method merges them into one flat collection. That makes it the tool for one-to-many transformations: one input row becomes zero, one or several output rows.
When to reach for it
Reach for it whenever a map is immediately followed by a flatten(1) or a collapse. Expanding orders into their line items, posts into their tags, or a date range into individual days are all natural fits. Returning an empty array from the callback drops that item entirely, which gives you filtering and expansion in a single pass.
The thing that trips people up
It collapses exactly one level, never more. If your callback returns an array of arrays, the inner arrays survive untouched — that is by design, but it surprises people who expect flatMap to behave like flatten with its infinite default depth.
Because the results are merged, string keys returned by different callback invocations can collide, with later items overwriting earlier ones. When the callback returns lists this never bites; when it returns keyed arrays, make the keys unique or use map plus an explicit merge.
Example
When to use it
- Expand each order into its individual line items for a flat invoice listing.
- Collect the unique tags used across a set of posts in one pass.
- Turn a list of date ranges into a single collection of individual dates.
Frequently asked questions
What is the difference between flatMap and map?
flatMap collapses the mapped results by one level, so a callback returning an array contributes several items to the output rather than one nested array. map always produces exactly one output item per input item.
Does flatMap flatten deeply nested results?
No, it collapses exactly one level. If your callback returns an array of arrays, the inner arrays remain intact — chain flatten() afterwards if you need to go deeper.
Can flatMap remove items as well as expand them?
Yes. Returning an empty array from the callback contributes nothing to the result, so that item is effectively dropped and filtering and expansion happen in a single pass.
More examples
flatMap versus map
The map output is two nested arrays, which unique() cannot meaningfully deduplicate. The flatMap output is the single list php, laravel, testing — one flat collection where unique() removes the repeated laravel. This side-by-side is the clearest illustration of what the collapse step buys you.
<?php
$posts = collect([
['title' => 'A', 'tags' => ['php', 'laravel']],
['title' => 'B', 'tags' => ['laravel', 'testing']],
]);
// map keeps the nesting: a collection of two arrays.
print_r($posts->map(fn (array $p) => $p['tags'])->all());
// flatMap merges them, so unique() can do its job.
print_r($posts->flatMap(fn (array $p) => $p['tags'])->unique()->values()->all());Returning an empty array to drop an item
Bob contributes nothing because his callback returns an empty array, so the output holds three entries — Ada:admin, Ada:billing and Cleo:support — and the count prints 3. Expansion and filtering happen in the same pass, which is why flatMap often replaces a filter followed by a map.
<?php
$users = collect([
['name' => 'Ada', 'roles' => ['admin', 'billing']],
['name' => 'Bob', 'roles' => []],
['name' => 'Cleo', 'roles' => ['support']],
]);
$assignments = $users->flatMap(fn (array $u) => array_map(
fn (string $role) => "{$u['name']}:{$role}",
$u['roles'],
));
print_r($assignments->all());
echo $assignments->count(), PHP_EOL;Expanding Eloquent relations
Each role carries several permissions, and flatMap merges them into one collection so unique('id') can deduplicate permissions granted by more than one role. Eager-load the relation first, or this triggers a query per role. This snippet needs a booted application with Eloquent, so it is shown rather than executed.
<?php
$permissions = $user->roles->flatMap(fn ($role) => $role->permissions)
->unique('id')
->values();
return $permissions->pluck('name')->all();
Discussion