7

I have a menu array, it's a multidimensional array, and I want to do some thing with every single item, so I tried array_walk_recursive. Here is the menu:

$menu = array(
    array(
        'name'=>'a',
        'url'=>'b',
    ),
    array(
        'name'=>'c',
        'url'=>'d',
        'children'=>array(
            array(
                'name'=>'e',
                'url'=>'f'
            )
        )
    )
);

But array_walk_recursive only let me handle every single element, but not array.

array_walk_recursive($menu, function(&$item){
    var_dump($item);//return a;b;c;d;e;f;g
});

What I want is like this:

array_walk_recursive_with_array($menu, function(&$item){
    var_dump($item);//return array('name'=>'a','url'=>'b');a;b;array('name'=>'c',...);c;d;...
    if(is_array($item) && isset($item['name'])){
        // I want to do something with the item.
    }
})

Is there any PHP native function implementation?

2
  • Might be a case for RecursiveArrayIterator Commented Jul 3, 2014 at 12:35
  • array_walk_recursive is to modify array. how would you want your $menu to be after array_walk_recursive is executed. Commented Jul 3, 2014 at 12:36

3 Answers 3

4

according to the array_walk_recursive documentation, you can't get the inner array key. One way to perform your need is to use array_walk and creating your own recursivity.

function HandleArray(&$value){
    if(is_array($value)){
        //Do something with all array
        array_walk($value,'HandleArray');
    }
    else{
       //do something with your scalar value
    }
}
array_walk(array($your_array),'HandleArray');
Sign up to request clarification or add additional context in comments.

2 Comments

Right. As per the PHP doc : "Any key that holds an array will not be passed to the function." Why that is, is beyond me. Seems counter-intuitive for a function named "recursive".
@mach128x Walking array-keys that hold an array recursively will blow up when arrays inside are self-referenced. You would at least need a maxDepth parameter to stop infinite recursion before it does. The HandleArray() example above will also need a protection from infinite recursion if the input array is from an unknown source.
1

You want to recursively search your array and perform some action every time your encounter an array that contains a key of name.

To demonstrate, here is a sample array that has a non-qualifying subarray ($array[1]) and three qualifying subarrays ($array[0], $array[2], and $array[2]['children']).

$array = [
    [
        'name' => 'a',
        'url' => 'b',
    ],
    [
        'no-name' => 'foo',
    ],
    [
        'name' => 'c',
        'url' => 'd',
        'children' => [
            [
                'name' => 'e',
                'url' => 'f'
            ]
        ]
    ]
];

To process the array, recursively access each node in the data structure. When an array is encountered, use isset() (or array_key_exists() if you need to respect potentially null values) to check if the array qualifies for your desired action.

Below is a script that will execute the recursive technique with the qualifying rules and add a new element whenever the rules are satsified. & is used in two places to indicate that a variable should be "modified by reference" -- this makes data mutation available outside of the scope of the custom function call.

Code: (Demo)

function recurseAll(&$node) {
    if (is_array($node)) {
        if (isset($node['name'])) {
            // do something with the qualifying array...
            $node[] = 'push a new element into array level';
        }
        foreach ($node as &$childNode) {
            recurseAll($childNode);
        }
    }
}

recurseAll($array);
var_export($array);

Output:

array (
  0 => 
  array (
    'name' => 'a',
    'url' => 'b',
    0 => 'push a new element into array level',      // added element to $array[0]
  ),
  1 => 
  array (                                            // didn't qualify
    'no-name' => 'foo',
  ),
  2 => 
  array (
    'name' => 'c',
    'url' => 'd',
    'children' => 
    array (
      0 => 
      array (
        'name' => 'e',
        'url' => 'f',
        0 => 'push a new element into array level', // added element to $array[2]['children']
      ),
    ),
    0 => 'push a new element into array level',     // added element to $array[2]
  ),
)

Comments

0

An infinite recursion safe-guard in @artragis example using array_walk() seems necessary. An ArrayHelper class example to reduce a given array to the array-values of a given array-key:

class ArrayHelper {
    /**
     * arrayFlattenToKeyValues - Like finding keys with array_walk_recursive()
     *   without the restriction "Any key that holds an array will not be passed to the function"
     * @see https://www.php.net/manual/en/function.array-walk-recursive.php#refsect1-function.array-walk-recursive-examples
     * @param array $deepArray
     * @param string $fromKey
     * @param int $maxDepth default = 10
     * @param array $accumulator default = []
     *
     * @return array
     */
    public static function arrayFlattenToKeyValues(
        array $deepArray,
        string $fromKey,
        int $maxDepth = 10,
        array $accumulator = []
    ): array {
        array_walk($deepArray, function ($value, $key) use (&$accumulator, $fromKey, $maxDepth) {
            if ($key === $fromKey) {
                $accumulator[] = $value;
            }
            if ($maxDepth > 0 && is_array($value)) {
                $accumulator = self::arrayFlattenToKeyValues($value, $fromKey, $maxDepth - 1, $accumulator);
            }
        });

        return $accumulator;
    }
}

This can probably be improved, simplified or done differently; please do!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.