'PHP object loaded as reference in foreach loop
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
Solution 1:[1]
Assignment or clone ?
Because, you're using objects, the problem is that $new_item = $item; doesn't create a new object, it creates a new reference of $item, named $new_item.
In the following example, $a and $b are the same object:
$a = new stdclass;
$b = $a;
var_dump($a, $b);
Output is:
object(stdClass)#1 (0) {...} // same object #1
object(stdClass)#1 (0) {...} // same object #1
Clone
You could use the keyword clone to create a new instance:
$a = new stdclass;
$b = clone $a; // Clone the object
var_dump($a, $b);
Output:
object(stdClass)#1 (0) {...} // object #1
object(stdClass)#2 (0) {...} // new object #2
So, in your case, you could use:
if ($item->id == 2) {
$clone = clone $item; // << Create a COPY of $item
$clone->title = 'new 2'; // Update the copy, not the reference
$calendar[$key] = $clone; // Add this copy to final array
// ...
}
A note about parameters
When you're using objects as parameters for some functions, objects are reference, so, the given object can be updated in that function. Here is a simple example (demo):
function updateObject(object $object): void {
$object->newProperty = true;
}
$obj = new stdClass;
var_dump($obj);
updateObject($obj);
var_dump($obj);
The code above gives the following (condensed) output:
object(stdClass)#1 (0) { }
object(stdClass)#1 (1) { ["newProperty"]=> bool(true) }
Further reading : Objects and references
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
