3

How can I change the value of an element with array_walk?

For instance, this is my array,

$items = array(
    0 => array( 
        "id" => "1",
        "title" => "parent 1",
       "children" => array()
        ),

    1 => array( 
        "id" => "2",
        "title" => "parent 2",
        "children" => array (
           0 => array( 
            "id" => "4",
            "title" => "children 1"
            ),
           1 => array( 
            "id" => "5",
            "title" => "children 2"
            ) 
        ),
   )
);

And I can change it with this below,

function myfunction(&$item,$key)
{
    if($item['id'] === '1')
    {
        $item['title'] = 'hello world en';
    }   
}


array_walk($items,"myfunction");

print_r($items);

But I have a nested children and I want to change the value in that too, and I will get error if I do this,

function myfunction(&$item,$key)
{
    if($item['id'] === '1')
    {
        $item['title'] = 'hello world en';
    }

    if($item['id'] === '4')
    {
        $item['title'] = 'hello world en';
    }


    foreach($item as $key => $value)
    {

        if(is_array($value))
        {
            myfunction($value,$key);
        }
    }

}

error,

Notice: Undefined index: id in ...index.php on line xx

Any idea what should I do if there is a nested children in an array?

1
  • 1
    In first place you should not have $arr['hardcodedKeyName'] before any check is done. You cannot be sure this key is present or not. You should recursively get through the last depth of array searching for id and change if present, then go to the beginning Commented Jul 15, 2014 at 13:21

5 Answers 5

8

You may achieve that with recursive call of your callback function. I've implemented sample with closure, like:

//replacement array:
$replace = [
  '1' => 'foo',
  '2' => 'bar',
  '5' => 'baz'
];

array_walk($items, $f=function(&$value, $key) use (&$f, $replace)
{
   if(isset($replace[$value['id']]))
   {
      $value['title'] = $replace[$value['id']];
   }
   if(isset($value['children']))
   {
      //the loop which is failing in question:
      foreach($value['children'] as $k=>&$child)
      {
         $f($child, $k);
      }
      //Proper usage would be - to take advantage of $f
      //array_walk($value['children'], $f);
   }
});

As you can see - all that you need is to pass value by reference and iterate it inside callback as a reference for foreach too.

Sign up to request clarification or add additional context in comments.

1 Comment

Interesting recursive solution.
2

When you add a line such as if (!isSet($item['id'])) var_dump($item); you will see why you get the undefined index.

Although I am not sure why you're doing this (how are you taking advantage of array_walk()?), to solve this, you could use something like the following:

function myfunction(&$item,$key)
{
    if ($item['id'] === '1')
    {
        $item['title'] = 'hello world en';
    }

    if ($item['id'] === '4')
    {
        $item['title'] = 'hello world en';
    }


    if (isSet($item['children']) && is_array($item['children']))
        array_walk($item['children'], __FUNCTION__);
}

Which will work with the example given.

Comments

1
foreach($item as $key => $value)
{

    if(is_array($value))
    {
        myfunction($value,$key);
    }
}

You walk through every key in your $item (id, title, children). But I guess what you want is moving through every ELEMENT of $value['children'] (value['children'][0], value['children'][1]), right? So it might be something like this:

if(is_array($value)){
   foreach($item['children'] as $key => $value){
      myfunction($value,$key);
   }
}

Comments

1

The problem is you're passing in your whole array of children, not each individual item of children. See this eval for how it should look. And here's the code:

<?php
$items = array(
    0 => array( 
        "id" => "1",
        "title" => "parent 1",
        "children" => array()
    ),

    1 => array( 
        "id" => "2",
        "title" => "parent 2",
        "children" => array (
           0 => array( 
            "id" => "4",
            "title" => "children 1"
            ),
           1 => array( 
            "id" => "5",
            "title" => "children 2"
            ) 
        ),
   )
);

function myfunction(&$item) {
  if($item['id'] == '1' || $item['id'] == '4') {
    $item['title'] = 'hello world en';
  }
  if( ! empty($item['children'])) {
    array_walk($item['children'], "myfunction");
  }
}

array_walk($items, "myfunction");

var_dump($items);

Comments

-1

In the code you posted you are not passing the reference through foreach. This should work with the code you posted.

foreach($item as $key => &$value)
{
    if(is_array($value)) {
        myfunction($value,$key);
    }
}

And to you don't see the undefined index, just check if that is setted before comparing the values:

if(isset($item['id'])){
    if($item['id'] === '1'){
      ...
    }
}

Online example

5 Comments

Not sure it's relevant
@RoyalBg well, I just tested online and worked. Ill update to add the link
The errors for undefined indices are still present, you saw? PHP Notice: Undefined index: id in /home/v5qmCF/prog.php on line 28 PHP Notice: Undefined index: id in /home/v5qmCF/prog.php on line 33 PHP Notice: Undefined index: id in /home/v5qmCF/prog.php on line 28 PHP Notice: Undefined index: id in /home/v5qmCF/prog.php on line 33
@RoyalBg Yes, of course there are better ways of doing this, and I didn't correct all errors, etc. Im just saying why his code is not updating the values in deep levels.
A part of the main question was about the undefined index error

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.