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
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
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
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
// ...
}
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
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;
}
}