Метод map() в коллекциях Laravel — просто о сложном

Метод map() из коллекций Laravel берёт каждый элемент коллекции, что-то с ним делает и складывает результат в новую коллекцию. Исходная коллекция при этом не меняется.

Суть в одном предложении: map — это конвейер, который получает элемент, возвращает новый элемент, и так для всех.

Самый простой пример — удвоим числа:

$numbers = collect([1, 2, 3, 4]);
$result = $numbers->map(function ($number) {
return $number * 2;
});
// [2, 4, 6, 8]


Анонимная функция вызывается для каждого элемента. То, что она вернёт через return, и попадёт в новую коллекцию на место старого элемента.

Строки работают так же:

$names = collect(['анна', 'борис', 'виктор']);

$result = $names->map(function ($name) {
return ucfirst($name);
});

// ['Анна', 'Борис', 'Виктор']


Ключ по-прежнему доступен. Второй параметр функции — ключ элемента:

$prices = collect([
'apple' => 100,
'milk' => 80,
]);

$result = $prices->map(function ($price, $key) {
return $key . ': ' . $price . ' руб.';
});

// ['apple: 100 руб.', 'milk: 80 руб.']


Типичный реальный пример — коллекция моделей из Eloquent. Превращаем объекты в компактные массивы для вывода:

$users = User::all();

$result = $users->map(function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
'phone' => $user->phone,
];
});


Чем map отличается от foreach. Формально — ничем, foreach делает то же самое через промежуточную переменную:

// то же самое через foreach
$result = [];
foreach ($names as $name) {
$result[] = ucfirst($name);
}


Разница в стиле: map говорит читающему «здесь элементы преобразуются один в один», foreach — «здесь может происходить что угодно». Поэтому для простых преобразований map читается быстрее.

Две вещи, о которых часто забывают:

  1. Обязательно нужен return. Если его забыть, на месте элемента окажется null, и коллекция наполнится пустыми значениями — классическая ошибка.
  2. map не меняет исходную коллекцию. Нужен изменённый оригинал — используйте transform().

Теперь про сложные примеры. В реальном коде в map часто передают внешние переменные через use:

$result = $chats->map(function ($chat) use ($userId, $unreadMap, $partners) {
return [
'id' => $chat->id,
'partner' => $partners[$chat->partner_id],
'unread_count' => $unreadMap[$chat->id] ?? 0,
];
});


Это тот же map, просто функция внутри «помнит» значения, объявленные снаружи, — за это отвечает use (...). Ничего нового тут нет: то же «каждый элемент — на выходе новый элемент», просто с участием дополнительных данных.

Правило на память: если нужно получить коллекцию той же длины, где каждый элемент пересобран по-новому, — это map.