W3docs

Полное руководство по функции array_walk_recursive() в PHP

Изучите array_walk_recursive() в PHP: применение callback-функции к каждому листу вложенных массивов, изменение по ссылке, примеры и подводные камни.

array_walk_recursive() применяет callback-функцию к каждому не-массивному значению (листу) в массиве, автоматически спускаясь во вложенные массивы. В отличие от ручного foreach, вам не нужно самостоятельно писать рекурсию, а в отличие от array_map(), функция может изменять исходный массив на месте, принимая каждое значение по ссылке.

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

Синтаксис

array_walk_recursive(array|object &$array, callable $callback, mixed $arg = null): true
  • $array — массив для обхода. Передаётся по ссылке, поэтому callback-функция может изменять его содержимое.
  • $callbackcallable, вызываемый для каждого листа и получающий ($value, $key). Объявите $value как &$value, чтобы редактировать массив на месте.
  • $arg — необязательный дополнительный аргумент, передаваемый (по значению) в callback-функцию в качестве третьего параметра.

Функция возвращает true. Только листовые значения передаются в callback — ключи, содержащие подмассивы, обходятся рекурсивно, но сами в callback не передаются.

Как функция обходит вложенные массивы

Callback вызывается для каждого скалярного элемента, а если элемент сам является массивом, array_walk_recursive() спускается в него. В следующем примере печатаются все пары key: value, включая находящиеся во вложенном массиве:

php— editable, runs on the server

Вывод:

0: a
1: b
0: c
1: d
2: e
3: f

Обратите внимание, что сам вложенный массив (содержащий c, d, e) не передаётся в callback — только его листья. Получаемые ключи являются ключами внутри каждого уровня, поэтому c, d, e снова выводятся с ключами 0, 1, 2.

Изменение значений по ссылке

Наиболее распространённый вариант использования этой функции — преобразование всей вложенной структуры на месте. Принимайте значение &$value по ссылке и присваивайте ему новое значение. В примере к каждой цене добавляется налог 10%, независимо от глубины вложенности:

<?php

$prices = [
    'fruit'  => ['apple' => 1.00, 'pear' => 2.00],
    'drinks' => ['water' => 0.50],
];

array_walk_recursive($prices, function (&$value, $key) {
    $value = round($value * 1.10, 2); // add 10% tax
});

print_r($prices);

?>

Вывод:

Array
(
    [fruit] => Array
        (
            [apple] => 1.1
            [pear] => 2.2
        )

    [drinks] => Array
        (
            [water] => 0.55
        )

)

Передача дополнительных данных через третий аргумент

Необязательный $arg передаётся в callback (по значению) третьим параметром — удобно для передачи конфигурации без использования замыкания. В примере строка-префикс задаётся один раз и используется для каждого листа:

<?php

$data = ['name' => 'ada', 'team' => ['bob', 'cara']];

array_walk_recursive($data, function ($value, $key, $prefix) {
    echo $prefix . ucfirst($value) . "\n";
}, ">> ");

?>

Вывод:

>> Ada
>> Bob
>> Cara

Поскольку $arg передаётся по значению, накапливать результаты между вызовами с его помощью невозможно. Чтобы накапливать значение, используйте захват переменной по ссылке через use (&$total):

<?php

$data = [1, [2, 3], 4];
$sum = 0;

array_walk_recursive($data, function ($value, $key) use (&$sum) {
    $sum += $value;
});

echo "Sum: $sum\n"; // Sum: 10

?>

Подводные камни

  • Рекурсия выполняется только для массивов. Лист — это всё, что не является массивом, включая объекты. Объект stdClass внутри данных передаётся в callback как единое значение, а не обходится рекурсивно.
  • Узлы-контейнеры (сами вложенные массивы) в callback не попадают. Если нужно работать с контейнерными массивами (а не только с листьями), используйте array_walk() или ручной рекурсивный foreach.
  • Для изменений необходим &$value. Без ссылки присвоения внутри callback отбрасываются, и исходный массив остаётся неизменным.
  • Ключи могут повторяться на разных уровнях. Получаемый $key является ключом на своём уровне, поэтому одно и то же значение ключа может встречаться в разных ветках.

Связанные функции

  • array_walk() — аналогичная идея, но только на один уровень вглубь.
  • array_map() — возвращает новый массив вместо изменения исходного.
  • array_filter() — оставляет элементы, прошедшие проверку.
  • PHP Arrays — основы работы с массивами и другие вспомогательные функции.

Практика

Практика
Что делает функция PHP array_walk_recursive?
Что делает функция PHP array_walk_recursive?
Was this page helpful?