Списки и массивы в PHP: различные методы обработки данных
В PHP массивы являются универсальной структурой данных, которая может представлять как упорядоченные списки (числовые индексы), так и ассоциативные коллекции. При работе со списками (последовательностями элементов) обычно используются числовые массивы, где ключи начинаются с нуля и возрастают на единицу. Эта статья рассматривает основные приёмы создания, модификации и анализа списков на основе встроенных функций и конструкций языка.
Основные подходы к работе со списками в PHP
Наиболее эффективное решение для массового преобразования элементов списка - использование встроенной функции array_map. Она применяет заданный callback к каждому элементу и возвращает новый массив, не изменяя исходный. Такой подход оптимизирован на уровне ядра PHP и даёт лаконичный код без явных циклов.
$numbers = [1, 2, 3, 4, 5];
$squares = array_map(fn($n) => $n * $n, $numbers);
print_r($squares);
Array
(
[0] => 1
[1] => 4
[2] => 9
[3] => 16
[4] => 25
)
Возможная проблема:
Если callback ожидает более одного аргумента (например,array_map с несколькими массивами), а передан только один, может возникнуть ошибка несоответствия сигнатуры. Рекомендуется использовать стрелочные функции или явные анонимные функции с одним параметром. Для сохранения ключей при использовании array_map с ассоциативным списком придётся дополнительно применить array_combine.
Цель и случаи использования:
Применяется для однотипного преобразования элементов (умножение, форматирование, извлечение поля) без побочных эффектов. Идеально подходит для конвейерной обработки данных.Как обойти все элементы упорядодоченного списка?
Простейший способ - конструкция foreach. Она безопасна для массива и автоматически перебирает все элементы.
$colors = ['red', 'green', 'blue'];
foreach ($colors as $index => $color) {
echo "$index: $color\n";
}
0: red 1: green 2: blue
Типичные ошибки:
Изменение массива внутриforeach (добавление или удаление элементов) может привести к непредсказуемому поведению. Для модификации лучше использовать цикл for с счётчиком или функцию array_walk. Также не рекомендуется полагаться на внутренний указатель массива после выхода из цикла.Цель:
Перебор списка для чтения или вывода данных без изменения структуры.
Как выделить элементы списка по критерию?
Функция array_filter возвращает элементы, для которых callback возвращает true. Ключи сохраняются, поэтому для получения числового индекса после фильтрации применяют array_values.
$numbers = [10, 15, 20, 25, 30];
$even = array_filter($numbers, fn($v) => $v % 2 === 0);
$evenIndexed = array_values($even);
print_r($evenIndexed);
Array
(
[0] => 10
[1] => 20
[2] => 30
)
Проблема:
По умолчаниюarray_filter удаляет элементы, равные false, без callback. Если оставить callback пустым, будут удалены 0, '', null, false, что не всегда ожидаемо. Лучше всегда передавать явную функцию.Цель:
Отбор подмножества элементов для последующей обработки или анализа.
Как присвоить значения первых элементов списка отдельным переменным?
Конструкция list() (или сокращённый синтаксис [...]) позволяет деструктуризировать массив в переменные.
$data = ['Alice', 28, 'designer'];
list($name, $age) = $data;
echo "Name: $name, Age: $age\n";
Name: Alice, Age: 28
Ошибка:
Если в массиве меньше элементов, чем переменных, будет сгенерировано предупреждениеUndefined array key. Стоит проверять длину массива функцией count перед деструктуризацией или использовать значения по умолчанию через array_pad.Цель:
Быстрое извлечение первых элементов (например, при разборе кортежа из базы данных или файла).
Как создать фиксированный список для экономии памяти?
Класс SplFixedArray создаёт массив строго заданной длины, что уменьшает накладные расходы по сравнению с обычным array. Индексация только числовая.
$fixed = new SplFixedArray(3);
$fixed[0] = 'PHP';
$fixed[1] = 'JS';
$fixed[2] = 'Python';
foreach ($fixed as $lang) {
echo "$lang\n";
}
PHP JS Python
Проблемы:
Нельзя изменить размер после создания (кромеsetSize(), но это создаёт новый объект). Попытка обратиться к несуществующему индексу вызывает исключение RuntimeException. С точки зрения API отличается от обычного массива - не поддерживает функции array_* напрямую, требуется преобразование через toArray().Цель:
Списки известного размера, где критична память (например, большие наборы векторов в математических расчётах).
Как вычислить общее значение на основе всех элементов списка?
Функция array_reduce последовательно свёртывает список в одиночное значение с помощью callback, принимающего накопленный результат и текущий элемент.
$prices = [100, 200, 150];
$total = array_reduce($prices, fn($carry, $item) => $carry + $item, 0);
echo "Total: $total\n";
Total: 450
Типичная ошибка:
Забыть указать начальное значение для$carry (третий аргумент). Если массив пуст, без начального значения будет выброшено ValueError в PHP 8+. Всегда передавайте начальное значение, соответствующее логике (0 для сумм, 1 для произведений, '' для конкатенации).Цель:
Агрегация данных (суммирование, поиск максимума, построение строки).
Продвинутые примеры работы со списками
В этом разделе представлены менее распространённые, но полезные приёмы обработки списков в PHP. Каждый пример снабжён кодом и выводом.
Пример 1. Сохранение ключей при преобразовании с array_map
Когда исходный список ассоциативный, array_map возвращает массив с числовыми индексами. Чтобы сохранить ключи, можно использовать array_combine в комбинации с array_map:
$items = ['a' => 10, 'b' => 20, 'c' => 30];
$doubled = array_combine(
array_keys($items),
array_map(fn($v) => $v * 2, $items)
);
print_r($doubled);
Array
(
[a] => 20
[b] => 40
[c] => 60
)
Пояснение:
Функцияarray_keys извлекает исходные ключи, а array_combine объединяет их с преобразованными значениями.
Пример 2. Объединение списков с сохранением перезаписи
Оператор + для массивов объединяет, но не перезаписывает существующие ключи. Для полного слияния с перезаписью используют array_merge.
$list1 = [0 => 'apple', 1 => 'banana'];
$list2 = [1 => 'cherry', 2 => 'date'];
$merged = array_merge($list1, $list2);
print_r($merged);
Array
(
[0] => apple
[1] => cherry
[2] => date
)
Пояснение:
array_merge переиндексирует числовые ключи, поэтому ключ 1 ('banana') заменён на 'cherry'. Для сохранения старых ключей при объединении ассоциативных массивов используют оператор +.
Пример 3. Сортировка пользовательским критерием
Функция usort сортирует массив, используя callback сравнения. Это удобно для сортировки списка объектов или сложных структур.
$users = [
['name' => 'John', 'age' => 25],
['name' => 'Anna', 'age' => 20],
['name' => 'Bob', 'age' => 30],
];
usort($users, fn($a, $b) => $a['age'] <=> $b['age']);
print_r($users);
Array
(
[0] => Array ([name] => Anna, [age] => 20)
[1] => Array ([name] => John, [age] => 25)
[2] => Array ([name] => Bob, [age] => 30)
)
Пояснение:
Космический оператор<=> возвращает -1, 0 или 1, что идеально подходит для функции сравнения. Массив сортируется по возрастанию возраста.
Пример 4. Разбиение списка на части
Функция array_chunk делит список на подмассивы заданного размера.
$nums = [1, 2, 3, 4, 5, 6, 7];
$chunks = array_chunk($nums, 3);
print_r($chunks);
Array
(
[0] => Array ([0] => 1, [1] => 2, [2] => 3)
[1] => Array ([0] => 4, [1] => 5, [2] => 6)
[2] => Array ([0] => 7)
)
Пояснение:
Последний чанк может быть меньше указанного размера. Вторым параметром можно передатьtrue для сохранения ключей из исходного списка.
Пример 5. Работа с очередью через SplQueue
Класс SplQueue (реализация очереди на основе двусвязного списка) оптимизирует операции enqueue (добавление) и dequeue (извлечение).
$queue = new SplQueue();
$queue->enqueue('first');
$queue->enqueue('second');
$queue->enqueue('third');
echo $queue->dequeue() . PHP_EOL; // first
echo $queue->dequeue() . PHP_EOL; // second
first second
Пояснение:
SplQueue поддерживает FIFO (первым пришёл - первым ушёл) и не требует переиндексации, в отличие от array_shift.
Пример 6. Рекурсивная обработка многомерного списка
Для применения функции ко всем элементам вложенных массивов можно написать рекурсивную обёртку над array_map.
function array_map_recursive(callable $callback, array $array): array {
$result = [];
foreach ($array as $key => $value) {
$result[$key] = is_array($value)
? array_map_recursive($callback, $value)
: $callback($value);
}
return $result;
}
$deep = [['a', 'b'], ['c', ['d', 'e']]];
$upper = array_map_recursive('strtoupper', $deep);
print_r($upper);
Array
(
[0] => Array ([0] => A, [1] => B)
[1] => Array ([0] => C, [1] => Array ([0] => D, [1] => E))
)
Пояснение:
Рекурсивный подход позволяет обрабатывать деревья любой глубины. Альтернатива - использованиеarray_walk_recursive, но он не возвращает новый массив.