Bug #75158 [Opn]: Cloning objects whith members that hold references to other members
| From: | danack@php.net | Date: | Tue, 05 Sep 2017 17:15:27 +0000 |
| Subject: | Bug #75158 [Opn]: Cloning objects whith members that hold references to other members | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-210961@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=75158&edit=1
ID: 75158
Updated by: danack@php.net
Reported by: krulis at ksi dot mff dot cuni dot cz
Summary: Cloning objects whith members that hold references
to other members
Status: Open
Type: Bug
Package: Class/Object related
Operating System: all
PHP Version: 7.1.9
Block user comment: N
Private report: N
New Comment:
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.
Previous Comments:
------------------------------------------------------------------------
[2017-09-05 15:27:26] 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.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=75158&edit=1