Home > Enterprise >  PHP object loaded as reference in foreach loop
PHP object loaded as reference in foreach loop

Time:02-11

I am looping through an object and i try to duplicate one of the items while changing one of it's variables.

But when i copy the original and then change the title in the new one, the old one changes along with it. Which it shouldn't, since i did not initialised it as a reference.

$calendar = array(
    (object)[
        'id' => 1,
        'title' => 'original 1',
    ],
    (object)[
        'id' => 2,
        'title' => 'original 2',
    ],
    (object)[
        'id' => 3,
        'title' => 'original 3',
    ],
);

foreach ($calendar AS $key => $item){
    if($item->id == 2){
        $item->title = 'new 2';
        array_splice($calendar, $key, 0, [1]);
        $calendar[$key] = $item;
    }
}

echo "<pre>";
print_r($calendar);
die();

I would expect the output of this to keep original 2 intact. But it changes it along with it.

(
    [0] => stdClass Object
        (
            [id] => 1
            [title] => original 1
        )

    [1] => stdClass Object
        (
            [id] => 2
            [title] => new 2
        )

    [2] => stdClass Object
        (
            [id] => 2
            [title] => new 2
        )

    [3] => stdClass Object
        (
            [id] => 3
            [title] => original 3
        )

)

Even if i make a new object and use that one to make the changes, it still changes the orignial.

foreach ($calendar AS $key => $item){
    if($item->id == 2){
        $new_item = $item;
        $new_item->title = 'new 2';
        array_splice($calendar, $key, 0, [1]);
        $calendar[$key] = $new_item;
    }
}

Now i could probably fix this by just making a new object from scratch and copy the values one by one in it. But where's the fun in that?

So my question is...Why does this happen? Even though i didn't cast $item as &$item

CodePudding user response:

$new_item = $item; doesn't create a new object.

In the following example, $a and $b are the same object.

$a = new stdclass;
$a->b = 2;
$b = $a;
var_dump($a,$b);

and output:

object(stdClass)#1 (1) {...} // same object #1
object(stdClass)#1 (1) {...} // same object #1

You could use clone to create a new instance:

$a = new stdclass;
$a->b = 2;
$b = clone $a; // Clone the object
var_dump($a,$b);

Output:

object(stdClass)#1 (1) {...} // object #1
object(stdClass)#2 (1) {...} // new object #2

So, in your case, you could use:

if ($item->id == 2) {
    $clone = clone $item;
    $clone->title = 'new 2';
    array_splice($calendar, $key, 0, [1]);
    $calendar[$key] = $clone;
}

CodePudding user response:

As simple PHP Object assignment does not create a new object. It simply creates a new pointer to the same object.

I think you want to use the clone keyword:

foreach ($calendar AS $key => $item){
if($item->id == 2){
    $new_item = clone $item;
    $new_item->title = 'new 2';
    array_splice($calendar, $key, 0, [1]);
    $calendar[$key] = $new_item;
}

}

  • Related