array_walk_recursive

Applies a user callback to every leaf value of a multidimensional array, descending into nested arrays.

Signature
array_walk_recursive(array|object &$array, callable $callback, mixed $arg = null): true
  • Added in PHP 5.0

Parameters

ParameterTypeDescription
$arrayarray|objectThe array to walk. Passed by reference, so the callback can modify leaf values.
$callbackcallableCalled once per leaf value as callback($value, $key) — or callback($value, $key, $arg) when arg is supplied. Declare the first parameter as &$value to change the array.
$argoptionalmixed= nullAn extra value passed as the third argument to every callback invocation.

Return value

trueAlways returns true. Since PHP 8.2.0 the declared return type is true; before that it was bool.

Errors

Throws ArgumentCountError if the callback requires more parameters than array_walk_recursive supplies. Emits E_WARNING if the callback declares its second or third parameter by reference.

Changelog

  • PHP 8.2.0The return type is true now; previously it was bool.

array_walk_recursive is array_walk that descends. Whenever it meets a value that is itself an array, it recurses into it instead of handing it to your callback. The callback therefore only ever sees leaf values — scalars, objects, nulls — never the intermediate arrays.

When to reach for it

It is the shortest way to sanitise or normalise a nested structure whose shape you do not want to change: trimming every string in a decoded JSON payload, casting every numeric string in a config tree, HTML-escaping a nested view model, or redacting values under sensitive keys. The array's structure is preserved exactly; only leaves change.

What trips people up

Because containers are skipped, you cannot use this function to inspect or rewrite the tree itself — you will never be called for 'db' in ['db' => ['host' => ...]]. If you need the branches too, write your own recursion or use RecursiveIteratorIterator with SELF_FIRST.

The $key passed to the callback is the leaf's own key, with no path information. Two leaves called 'name' at different depths are indistinguishable, so key-based logic on deep arrays is usually a bug waiting to happen.

As with array_walk, edits require &$value, and empty arrays simply produce no callback calls at all.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Trim whitespace from every string in a decoded JSON request body of unknown depth.
  • HTML-escape every leaf of a nested view model before rendering a template.
  • Redact or mask values throughout a nested config dump before logging it.

Frequently asked questions

What is the difference between array_walk and array_walk_recursive?

array_walk visits only the top level and hands nested arrays to your callback as values, while array_walk_recursive descends into them and calls your callback only for leaf values. Use the recursive form when the array depth is unknown or irrelevant.

Does array_walk_recursive give me the full key path?

No. The callback receives only the leaf's own key, with no information about its parents. If you need the path, use a RecursiveIteratorIterator or write your own recursion that carries the path along.

Why does my callback never run on empty nested arrays?

An empty array has no leaves, so there is nothing to call the callback with. The function still returns true and leaves the empty array in place.

More examples

Flattening leaves into a list

The closure captures $flat by reference and appends each leaf as it is visited, giving Array ( [0] => 1 ... [5] => 6 ) and a sum of 21. Note the nested arrays at depth 1 and 2 never reach the callback — only the six integers do.

Example · php
<?php
$tree = [1, [2, 3, [4, 5]], 6];
$flat = [];

array_walk_recursive($tree, function ($value) use (&$flat) {
    $flat[] = $value;
});

print_r($flat);
echo array_sum($flat), "\n";

Containers are never passed to the callback

Only two lines print — name and the tags entry 0 — proving that 'user' and 'tags' themselves are traversed silently. This is why the function cannot be used to rewrite keys or detect empty branches.

Example · php
<?php
$data = ['user' => ['name' => 'Ada', 'tags' => ['admin']]];

array_walk_recursive($data, function ($value, $key) {
    echo "leaf: $key = ", var_export($value, true), "\n";
});

Masking values with the third argument

The $secret list arrives as the callback's third parameter, so the list of sensitive field names does not have to be captured in a closure. The output keeps id => 7 intact while pan and cvv become runs of asterisks of the same length.

Example · php
<?php
$payload = ['id' => 7, 'card' => ['pan' => '4111111111111111', 'cvv' => '123']];
$secret = ['pan', 'cvv'];

array_walk_recursive($payload, function (&$v, $k, $fields) {
    if (in_array($k, $fields, true)) { $v = str_repeat('*', strlen((string) $v)); }
}, $secret);

print_r($payload);

Discussion

  • Be the first to comment on this lesson.