Почему я предпочитаю функции массива циклам
foreach
. И хотя синтаксис не такой красивый, как в JavaScript, считаю, что они работают лучше, чем "обычный" цикл.Что такое функции массива
В PHP есть довольно много функций для работы с массивами, каждая из которых имеет своё собственное применение. В этой статье расскажу о функциях, которые обходят массив и выполняют функцию для каждого элемента в массиве.
Можно вспомнить такие функции, как array_reduce
, array_map
, array_filter
и т. д. Каждая из этих функций выполняет определённые действия для каждого элемента массива и возвращает новое значение.
Зачем использовать функцию массива
Сообщение о намерениях
Думаю, наиболее важным фактором является то, что с помощью функции массива вы сообщаете о своих намерениях. Вызов функции даёт понять, чего вы пытаетесь добиться. array_filter
? Вы фильтруете массив. array_map
? Вы изменяете каждый элемент массива, но сохраняете его структуру. array_reduce
? Вы изменяете массив в новую структуру.
Это означает, что читая вызов функции, можно понять, что кто-то пытается сделать, и таким образом сократить ментальное пространство, необходимое для понимания функции.
Всё происходит внутри функции
Всё, что делает функция массива, происходит внутри функции. Взгляните на следующий пример. В части цикла переменная $newNumbers
не является частью цикла, а находится над ним. Хотя в данном примере это не так уж и важно, я видел, как объявление новой переменной находилось на значительном расстоянии от цикла, из-за рефакторинга и других вещей.
$newNumbers = [];
foreach ($array as $key => $number) {
$newNumbers[$key] = $number + 2;
}
$newNumbers = array_map(
fn (int $number) => $number + 2,
$array
);
Меньше вероятность побочных эффектов
В PHP можно написать два типа замыканий: с помощью синтаксиса function($parameter) use($uses)
и fn($parameters)
. Поскольку во втором случае допускается только 1 оператор, вероятность возникновения побочных эффектов уже гораздо ниже. А в первом примере всё, что не передаётся в качестве функции, нужно добавлять через use()
. Это означает, что можно чётко видеть, что использует этот цикл. И use
не передаёт значения по ссылке (по умолчанию). Так что, если в цикле изменить переменную, на следующей итерации она обнуляется. И нет никакого шанса случайно переопределить переменную, которая находится вне цикла.
$value = 3;
$new = [];
foreach ($array as $value) {
$new[] = $value +1;
}
// Теперь $value - последний элемент массива;
$value = 3;
array_map(function (int $value) {
return $value + 1;
}, $array);
// $value по-прежнему 3;
Когда не стоит использовать функцию массива
Эти функции не всегда оказываются лучшим решением. Например, если необходимо выполнить фильтрацию и сопоставление, то это можно сделать в одном цикле foreach
. Но если использовать array_filter
и array_map
, то это приведёт к двойному обходу массива. Хотя для большинства приложений это, вероятно, не является большим узким местом, но если у вас миллионы элементов, это может иметь значение. Например, при цикле на 100 тыс. элементов, где вызов фильтра отфильтровывал 10 %, я получил разницу во времени выполнения от 0,002
до 0,003
секунды на моей машине.
А иногда нужно, чтобы функция управляла несколькими переменными и имела побочные эффекты, в этом случае лучше использовать цикл.
Но если нужно отфильтровать массив, изменить элементы на другие или свести
его к другой структуре, использование функции массива сделает его более читаемым, удобным в сопровождении и менее подверженным ошибкам, чем цикл.