Arrays7 min readExamples run on PHP 8.5.10

array_walk_recursive()

Learn how array_walk_recursive() visits every leaf value of a nested array in PHP 8.4, how to modify values by reference, and which mistakes to avoid.

Signature

array_walk_recursive(array|object &$array, callable $callback, mixed $arg = null): true

Purpose

array_walk_recursive() calls a callback on every non-array element of a nested array. When it meets an element that is itself an array, it descends into it instead of passing it to the callback. Use it when you want to inspect or change all leaf values in a tree-like structure, such as decoded JSON, configuration data or form input, without writing your own recursive function.

Signature

Parameters and defaults

  • $array is taken by reference. Normally you pass an array variable. An object is also accepted and is treated as if it had been cast to an array first. Even then, the function does not recurse into inner objects.
  • $callback is called for each leaf. It usually receives the value first and the key second. Declare the first parameter by reference (&$value) if you want your changes written back to the original array.
  • $arg is optional and defaults to null. If you supply it, PHP passes it to the callback as the third argument. This is a tidy way to hand extra data such as a multiplier to the callback without a closure.

Return value and failure cases

The function always returns true. Since PHP 8.2 the declared return type is true; earlier it was bool. Because the result never varies, there is no point in testing it. The results of your work live in the array you passed by reference or in variables you captured in the callback.

Failures show up as exceptions rather than return values. A callback that is not callable raises a TypeError. A callback with a required third parameter will raise an ArgumentCountError if you did not supply $arg.

Example 1: summing leaf values

A closure that captures a variable by reference can accumulate a result while the walk proceeds.

Example
<?php
$data = ['a' => 1, 'b' => ['c' => 2, 'd' => ['e' => 3]], 'f' => 4];
$total = 0;
array_walk_recursive($data, function ($value, $key) use (&$total) {
    $total += $value;
});
echo $total, "\n";
Output
10

The callback sees 1, 2, 3 and 4 at any depth, so the total is 10.

Example 2: changing values in place with an extra argument

The by-reference first parameter lets the callback overwrite each leaf. The third callback parameter receives $arg.

Example
<?php
$prices = ['book' => 10, 'items' => ['pen' => 2, 'bag' => 20]];
array_walk_recursive($prices, function (&$value, $key, $factor) {
    $value = $value * $factor;
}, 3);
echo json_encode($prices, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"book":30,"items":{"pen":6,"bag":60}}

The nested structure is preserved, and only the leaf values change.

Example 3: which keys are visited

Keys that hold arrays are never passed to the callback, and an empty array contributes nothing because it has no leaves.

Example
<?php
$config = ['db' => ['host' => 'localhost', 'port' => 3306], 'debug' => false, 'tags' => []];
$seen = [];
array_walk_recursive($config, function ($value, $key) use (&$seen) {
    $seen[] = $key;
});
echo json_encode($seen), "\n";
Output
["host","port","debug"]

The keys db and tags are absent from the result. Only host, port and debug are reported.

Edge cases

  • Array keys are hidden. If you need to know which branch a leaf belongs to, the callback only sees the immediate key. Track the path yourself with a different technique, such as your own recursive function.
  • Keys cannot be changed. The walk gives you a reference to values only. To rename keys you must build a new array.
  • Objects are not entered. An object stored as a value is passed to the callback as a leaf. Its properties are not walked.
  • Adding or removing elements while walking is not what this function is designed for. Use it to transform existing leaves.
  • Empty arrays are traversed but produce no callback calls.

Common mistakes

  1. Forgetting the reference. Writing function ($value, $key) and assigning to $value changes only a local copy. Use &$value when you need to modify the original.
  2. Expecting a result. The function returns true, not a new array. If you want a transformed copy, copy the array first and walk the copy.
  3. Passing built-in functions blindly. The callback receives the key as the second argument. A function like trim interprets a second argument as something else, so wrap it in a closure that ignores the key.
  4. Expecting parent keys. Keys that hold arrays are skipped, so you cannot react to them in the callback.
  5. Omitting $arg when the callback requires it. Either supply the argument or give the callback parameter a default value.
  • array_walk() applies a callback to the top level only.
  • array_map() returns a new array and does not modify the original, but it does not recurse by itself.
  • array_reduce() folds a flat array into one value.
  • RecursiveIteratorIterator with RecursiveArrayIterator offers more control, including access to depth.

Recap

array_walk_recursive() visits each leaf of a nested array, passing the value, the key and an optional extra argument to your callback. Use a by-reference first parameter to modify values in place, or capture variables by reference to collect results. It always returns true, skips keys that hold arrays, and does not descend into inner objects.

Tested examples

Summing leaf values in a nested array
<?php
$data = ['a' => 1, 'b' => ['c' => 2, 'd' => ['e' => 3]], 'f' => 4];
$total = 0;
array_walk_recursive($data, function ($value, $key) use (&$total) {
    $total += $value;
});
echo $total, "\n";
Output
10
Changing values in place with an extra argument
<?php
$prices = ['book' => 10, 'items' => ['pen' => 2, 'bag' => 20]];
array_walk_recursive($prices, function (&$value, $key, $factor) {
    $value = $value * $factor;
}, 3);
echo json_encode($prices, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"book":30,"items":{"pen":6,"bag":60}}
Seeing which keys reach the callback
<?php
$config = ['db' => ['host' => 'localhost', 'port' => 3306], 'debug' => false, 'tags' => []];
$seen = [];
array_walk_recursive($config, function ($value, $key) use (&$seen) {
    $seen[] = $key;
});
echo json_encode($seen), "\n";
Output
["host","port","debug"]