php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #48460 Referencing an object property causes behaviour change after clone
Submitted: 2009-06-03 13:29 UTC Modified: 2012-01-11 14:38 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: ben at last dot fm Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: 5.2.9 OS: Linux
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: ben at last dot fm
New email:
PHP Version: OS:

 

 [2009-06-03 13:29 UTC] ben at last dot fm
Description:
------------
If you create a reference to a property of an object, then clone 
the object, the reference will become bi-directional and the property 
will no longer behave like a property.

This does not happen if you create, then destroy, the reference BEFORE 
cloning. 

This persists even if you unset the reference AFTER cloning.

Reproduce code:
---------------
<?php
class A { var $list; }

$a = new A;
$a->list = array( 1, 1, 1, 1, 1 );

$b = clone $a;
$link =& $a->list;
unset($link);
$c = clone $a;
$link =& $a->list;
$d = clone $a;
unset($link);
$e = clone $a;

$b->list = array(2,2,2,2,2);
$c->list = array(3,3,3,3,3);
$d->list = array(4,4,4,4,4);
$e->list = array(5,5,5,5,5);

echo "$a\n$b\n$c\n$d\n$e\n";

Expected result:
----------------
{1}
{2}
{3}
{4}
{5}

Actual result:
--------------
{5}
{2}
{3}
{5}
{5}

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-06-03 13:32 UTC] ben at last dot fm
More minimal test case:

<?php
class A { var $p; }

$a = new A;
$a->list = 1;

$b = clone $a;
$link =& $a->p;
unset($link);
$c = clone $a;
$link =& $a->p;
$d = clone $a;
unset($link);
$e = clone $a;

$b->p = 2;
$c->p = 3;
$d->p = 4;
$e->p = 5;

echo "$a->p\n$b->p\n$c->p\n$d->p\n$e->p\n";
 [2009-06-03 13:34 UTC] ben at last dot fm
Sorry, put this in the wrong category.
 [2009-06-03 13:54 UTC] colder@php.net
This is quite expected, that's basically the same as:

$a = array(2);
$d = &$a[0];

$a_copy = $a;
$a_copy[0]++;

echo $a[0],$d; // 3 3

You can do a deep copy using the __clone hook.

OTOH I'm not sure if clone shouldn't separate the properties directly, instead of simply assigning them.


 [2009-06-03 15:26 UTC] ben at last dot fm
Hmm.

The bug is that you can alter the behaviour of clone (that is, force $d-
>list to be copied-by-reference instead of copied-by-value) merely by 
creating any other reference to $a->list. 'clone' is, therefore, the 
only language construct (that I know of) which is capable of this, and 
is NOT the same as "$b = new A; $b->list = $a->list". 

There is in fact no way to tell whether a property is a reference or not 
without cloning the entire object and seeing what happens when you 
change the clone's property; or by forcibly unsetting and resetting the 
property.
 [2009-09-18 19:01 UTC] jani@php.net
Please try using this snapshot:

  http://snaps.php.net/php5.3-latest.tar.gz
 
For Windows:

  http://windows.php.net/snapshots/


 [2009-09-26 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2012-01-11 14:06 UTC] matteopuppis at gmail dot com
More simple code:
<?php
class Obj {
    
}

$a = new Obj();
$a->test[0] = 'pippo';
$b = clone $a;
$b->test[0] = 'pluto';
echo ($a->test[0].'<br /><br />');

$c = new Obj();
$c->test[0]->prova = 'pippo';
$d = clone $c;
$d->test[0]->prova = 'pluto';
echo ($c->test[0]->prova);
?>

Expected result: "pippo pippo"
Actual result: "pippo pluto"
 [2012-01-11 14:38 UTC] ben at last dot fm
-Status: No Feedback +Status: Closed
 [2012-01-11 14:38 UTC] ben at last dot fm
Sorry matteo, that's not got anything to do with the bug I was reporting. Your 
example doesn't include setting a reference, so it's not the same bug.

I can confirm this bug still exists in PHP 5.3.5.

Here is a real minimal test case:


class A { var $p; }
$a = new A;
$a->p = 'expected';
$x =& $a->p;
$b = clone $a;
$a->p = 'unexpected;
echo $b->p; // prints 'unexpected'; b is sharing references with a, due to an 
inbound reference from outside, so clone behaviour changes for that property.

You can also cause clone behaviour to change using the following highly bizarre 
incantation:

$a = new A;
$a->p =& $a->p; // turn the property into a reference with a refcount of 1.
$b = clone $a;
$a->p = 1;
$b->p = 2;
echo $a->p; // gives 2.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Fri Jul 04 19:01:37 2025 UTC