array_walk_recursive not descending into nested array

Viewed 570

I want to modify the value pointed to by a key. The value is an array, possibly nested. The key may itself be arbitrarily deep in a nested array structure.

This code:

print("Walk a nested array array_walk_recursive\n");
$a=array("a"=>1,"b"=>2,"c"=>4,"d"=>array("d2_1"=>1,"d2_2"=>array("d3_1"=>1,"d3_2"=>2)));
var_dump($a);
$c=0;
array_walk_recursive($a,function($a,$b) use (&$c){
    $c++;
    print($c . ": " . $b . ' type: ' . gettype($a) . "\n");
});

Gives this output:

Walk a nested array array_walk_recursive

array(4) {
  'a' =>
  int(1)
  'b' =>
  int(2)
  'c' =>
  int(4)
  'd' =>
  array(2) {
    'd2_1' =>
    int(1)
    'd2_2' =>
    array(2) {
      'd3_1' =>
      int(1)
      'd3_2' =>
      int(2)
    }
  }
}
1: a type: integer
2: b type: integer
3: c type: integer
4: d2_1 type: integer
5: d3_1 type: integer
6: d3_2 type: integer

Whereas I need these additional outputs:

d type: array
d2_2 type: array

Is there a way to do this with array_walk_recursive or another built in function?

The output I need is clearly visible in the var_dump structure, perhaps there is a way to use that?

Related Questions Recursive array walk to fetch multi-level array key

2 Answers

The builtins are the iterator classes. The RecursiveIteratorIterator flattens the iteraration over a traversable tree entering and leaving children automatically. Note that the default mode is to iterate over leaves only. RecursiveIteratorIterator::SELF_FIRST or RecursiveIteratorIterator::CHILD_FIRST changes that behavior.

$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a), RecursiveIteratorIterator::SELF_FIRST);

while($it->valid())
{
  $v = $it->current();
  echo $it->key() . ( is_scalar($v) ? " => $v" : '') . '  type: ' . gettype($it->current()) . PHP_EOL;
  $it->next();
}

Output using your given array:

a => 1  type: integer
b => 2  type: integer
c => 4  type: integer
d  type: array
d2_1 => 1  type: integer
d2_2  type: array
d3_1 => 1  type: integer
d3_2 => 2  type: integer

The array_walk_recursive() visits only leaf nodes.

You can easily solve this issue using recursion. Here is an example (use PHP 7 to run, the older versions have is_array or is_object). In PHP you can iterate over public object properties.

function walk($anything) {
    if (is_iterable($anything)) {
        foreach ($anything as $key => $value) {
            echo "\n" . $key . ': ' . gettype($value);
            walk($value);
        }
    } else {
        echo ': ' . $value;
    }
}

You can pass number of iterations or even a stack deepness.

Related