В чём разница между array_map, array_filter и array_reduce?
array_map преобразует каждый элемент и возвращает массив той же длины; array_filter отбирает элементы по условию, сохраняя ключи; array_reduce сворачивает массив в одно значение произвольного типа.
Три функции высшего порядка в PHP
array_map, array_filter и array_reduce — стандартные функции PHP для работы с массивами в функциональном стиле. Каждая решает свою задачу: преобразование, отбор и свёртка. Правильный выбор делает код лаконичным и читаемым.
array_map — преобразование элементов
array_map(callable $callback, array $array): array применяет функцию к каждому элементу и возвращает новый массив той же длины. Исходный массив не изменяется.
$prices = [100, 200, 350];
$withVat = array_map(fn(int $p) => (int)($p * 1.2), $prices);
// [120, 240, 420]
Если передать null в качестве колбэка и несколько массивов, функция объединяет их поэлементно:
$a = [1, 2, 3];
$b = ['a', 'b', 'c'];
$zipped = array_map(null, $a, $b);
// [[1,'a'], [2,'b'], [3,'c']]
array_filter — фильтрация элементов
array_filter(array $array, ?callable $callback, int $mode = 0): array возвращает подмассив, сохраняя только элементы, для которых колбэк вернул true. Ключи оригинального массива сохраняются — это важное отличие от array_map.
$nums = [0, 1, 2, 3, 4, 5];
$even = array_filter($nums, fn(int $n) => $n % 2 === 0 && $n !== 0);
// [2 => 2, 4 => 4]
// Сброс ключей при необходимости:
$even = array_values($even); // [2, 4]
Без колбэка удаляет «ложные» значения (0, "", null, false, []):
$clean = array_filter([0, 1, '', 'hello', null, false]);
// [1 => 1, 3 => 'hello']
array_reduce — свёртка в одно значение
array_reduce(array $array, callable $callback, mixed $initial = null): mixed последовательно применяет функцию к аккумулятору и каждому элементу, возвращая итоговое значение произвольного типа.
$orders = [
['amount' => 500, 'paid' => true],
['amount' => 300, 'paid' => false],
['amount' => 800, 'paid' => true],
];
$totalPaid = array_reduce(
$orders,
fn(int $carry, array $order) => $order['paid'] ? $carry + $order['amount'] : $carry,
0
);
// 1300
С помощью array_reduce можно собрать массив, строку, объект — любой тип:
$words = ['hello', 'world', 'php'];
$index = array_reduce(
$words,
function (array $carry, string $word): array {
$carry[$word[0]] = $word; // группировка по первой букве
return $carry;
},
[]
);
// ['h' => 'hello', 'w' => 'world', 'p' => 'php']
Сравнительная таблица
- array_map: вход — массив длины N, выход — массив длины N. Задача: трансформация каждого элемента.
- array_filter: вход — массив длины N, выход — подмассив длины ≤ N с сохранёнными ключами. Задача: отбор по условию.
- array_reduce: вход — массив длины N, выход — скалярное значение или структура произвольного типа. Задача: агрегация/свёртка.
Подводные камни
- array_filter сохраняет ключи — после фильтрации числовые ключи становятся разрозненными. Если нужен «чистый» индексированный массив, оберните в
array_values(). - array_map с null и несколькими массивами меняет поведение радикально — результат массив массивов. Это не очевидно и ломает ожидания при рефакторинге.
- array_reduce без $initial — если массив пуст, вернёт
null, а не 0 или []. Всегда передавайте начальное значение явно. - Потеря производительности на больших массивах — все три функции создают новые структуры. При обработке миллионов элементов предпочтительны генераторы (
yield) или потоковая обработка. - array_map не передаёт ключи в колбэк (по умолчанию). Если нужен ключ, используйте
array_walkилиforeach. - array_filter без колбэка удаляет 0 и "0" — это частая ошибка при обработке числовых строк или идентификаторов.
- Цепочки вместо одного прохода — map + filter + reduce делают три прохода по массиву. Для тяжёлых данных рассмотрите Laravel Collections или один
foreach. - Нет short-circuit в array_filter/array_map — колбэк вызывается для каждого элемента без возможности досрочного выхода. Для поиска первого совпадения используйте
foreachсbreakилиarray_search.
Common mistakes
- Сводить array map filter reduce к названию метода без lifecycle и failure path.
- Игнорировать модель runtime: интерпретируемый runtime PHP 8.x, обычно запускаемый как отдельный запрос в FPM, CLI или worker-процессе.
- Не отделять validation, authorization, transaction boundary и business logic.
- Менять похожие API местами без учёта семантики ошибок и ownership.
What the interviewer is testing
- Объясняет array map filter reduce через конкретную точку lifecycle в PHP.
- Приводит корректный минимальный пример без вымышленных методов или callbacks.
- Называет edge cases: пустые значения, ошибки, транзакции, безопасность или concurrency.