Estoy recorriendo un objeto e intento duplicar uno de los elementos mientras cambio una de sus variables.
Pero cuando copio el original y luego cambio el título en el nuevo, el anterior cambia junto con él. Lo cual no debería, ya que no lo inicialicé como referencia.
$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(); Espero que la salida de esto mantenga intacto el original 2 . Pero lo cambia junto con él.
( [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 ) )Incluso si creo un nuevo objeto y lo uso para hacer los cambios, todavía cambia el original.
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; } }Ahora probablemente podría arreglar esto simplemente haciendo un nuevo objeto desde cero y copiando los valores uno por uno en él. Pero, ¿dónde está la diversión en eso?
Entonces mi pregunta es... ¿Por qué sucede esto? Aunque no puse $item como &$item
Debido a que está usando objetos, el problema es que $new_item = $item; no crea un nuevo objeto, crea una nueva referencia de $item , llamada $new_item .
En el siguiente ejemplo, $a y $b son el mismo objeto:
$a = new stdclass; $b = $a; var_dump($a, $b);La salida es:
object(stdClass)#1 (0) {...} // same object #1 object(stdClass)#1 (0) {...} // same object #1 Podrías usar la palabra clave clone para crear una nueva instancia:
$a = new stdclass; $b = clone $a; // Clone the object var_dump($a, $b);Producción:
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 // ... }Cuando usa objetos como parámetros para algunas funciones, los objetos son referencia , por lo que el objeto dado se puede actualizar en esa función. Aquí hay un ejemplo simple ( demostración ):
function updateObject(object $object): void { $object->newProperty = true; } $obj = new stdClass; var_dump($obj); updateObject($obj); var_dump($obj);El código anterior da la siguiente salida (condensada):
object(stdClass)#1 (0) { } object(stdClass)#1 (1) { ["newProperty"]=> bool(true) }Lectura adicional: Objetos y referencias
Como la simple asignación de objetos PHP no crea un nuevo objeto. Simplemente crea un nuevo puntero al mismo objeto.
Creo que quieres usar la palabra clave clone :
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; } }