Collection::map
Runs a callback over every item and returns a new collection of the returned values.
public function map(callable $callback): staticParameters
| Parameter | Type | Description |
|---|---|---|
$$callback | callable | Called as ($value, $key) for each item; its return value becomes the new value for that key. |
Return value
Illuminate\Support\CollectionA new collection of the callback's return values, keeping the original keys.
This is the workhorse transformation. Each item is handed to the callback along with its key, and whatever the callback returns becomes the new value at that same key. The number of items and the keys are unchanged — only the values are replaced.
When to reach for it
Any time the shape of the data has to change: models into arrays for an API response, raw prices into formatted strings, database rows into value objects. If you only need one field out of each row, pluck is shorter; if you need to change the keys as well, use mapWithKeys.
What trips people up
It returns a new collection and leaves the original alone — transform is the in-place version. Because the keys survive, mapping over a filtered collection gives you a collection with gaps in its numeric keys, which encodes to a JSON object rather than an array; call values() before serialising.
The callback is invoked with two arguments. That is fine for closures, but internal functions such as strtoupper reject the extra argument; the framework catches the resulting ArgumentCountError and retries with one argument, so string callables still work. Forgetting to return inside the callback silently fills the collection with nulls.
Example
When to use it
- Convert a collection of models into the array shape an API response expects.
- Format prices, dates or names for display while keeping the collection chainable.
- Add a derived field to every row, such as a computed total or a full name.
Frequently asked questions
Does it modify the original collection?
No, it returns a new collection and leaves the original as it was. Use transform() when you want the original changed in place.
Can the callback see the key?
Yes — it is called as ($value, $key), so declaring a second parameter gives you the key. Closures may safely declare only the first parameter.
Why does my result serialise as a JSON object instead of an array?
Because the original keys are preserved, and after a filter those numeric keys have gaps, which json_encode renders as an object. Call values() first to re-index.
More examples
Reshaping rows
Each row is replaced by a smaller, differently shaped row. The output has two entries keyed 0 and 1 — the same keys as the input — with only the 'name' and 'role' fields, which is the usual way to build an API payload from raw records.
<?php
$users = collect([
['first' => 'Ada', 'last' => 'Lovelace', 'admin' => true],
['first' => 'Linus', 'last' => 'Torvalds', 'admin' => false],
]);
$payload = $users->map(fn (array $u) => [
'name' => $u['first'] . ' ' . $u['last'],
'role' => $u['admin'] ? 'admin' : 'member',
]);
print_r($payload->all());Using the key argument
The second argument is the key, which is what lets each line label itself. The output is three lines, EU: 1,200 / US: 900 / APAC: 450, still keyed by region should you need to look one up afterwards.
<?php
$totals = collect([
'eu' => 1200,
'us' => 900,
'apac' => 450,
]);
$lines = $totals->map(
fn (int $amount, string $region) => strtoupper($region) . ': ' . number_format($amount)
);
echo $lines->implode("\n") . PHP_EOL;New collection, not a mutation
Discarding the return value of this method changes nothing — the first dump is still [5, 0, 3]. transform() is the in-place counterpart and mutates the original, so the second dump is [15, 10, 13].
<?php
$stock = collect([5, 0, 3]);
$stock->map(fn (int $qty) => $qty + 10);
print_r($stock->all());
$stock->transform(fn (int $qty) => $qty + 10);
print_r($stock->all());
Discussion