|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2017-09-05 15:27 UTC] krulis at ksi dot mff dot cuni dot cz
Description:
------------
When I have an object and one member variable is a reference to another member variable, clone of such object is not correctly constructed. In the test script, you can see Foo class with two members: $data and $ref. $ref is set to be a reference to $data of the same object.
When object of foo is cloned. The clone's $data is in fact reference to original object's $data. In other words, clone should in fact do $c->data = $o->data (shallow copy by = operator), but instead, it seems like $c->data =& $o->data.
Note that the references are in fact not used, and when they are removed (line in the constructor is commented), it starts to work correctly again. I have also tested integer values in $data (beside arrays) and they work all the same.
This behavior was observed on Windows 7.1.9 and Linux 5.6.26. A similar problem was described in #66040, but I am not sure, whether they are connected or not.
Test script:
---------------
<?php
class Foo {
public $data = [];
public $ref;
public function __construct()
{
$this->ref =& $this->data;
}
}
$o = new Foo();
$c = clone($o);
$o->data[] = 42;
var_dump($c->data); // writes out an array with one item (42), even though the array should be empty
Expected result:
----------------
I would expect that $c->data === [] at the end.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Oct 26 17:00:01 2025 UTC |
I don't think this is a bug......it's just that references are really, really, confusing. For the line "$this->ref =& $this->data;" this does not create a variable called 'ref' that is a reference to the 'real' variable called 'data'. Instead it moves the variable elsewhere and sets both 'data' and 'ref' to be a reference to that variable. This in unlike other programming languages that use pointers. In those, creating a point to a value does not affect how the original value is stored. But in PHP, creating a reference does make the original property become a reference. A workaround for this is to explicitly copy the values, destroy the variable with unset() to remove the fact that it's a reference to another variable, and then copy the values over. class Foo { public $data; public $ref; public function __construct() { $this->data = []; $this->ref = &$this->data; } public function __clone() { $values = (array)$this->data; unset($this->data); $this->data = [$values]; $this->ref = &$this->data; } } $o = new Foo(); $o->data[] = 1; $c = clone($o); $o->data[] = 42; var_dump($c->data); Or you could just not use references.