Метод 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 читается быстрее.
Две вещи, о которых часто забывают:
- Обязательно нужен return. Если его забыть, на месте элемента окажется
null, и коллекция наполнится пустыми значениями — классическая ошибка. - 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.