php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #11909 Object Copied By Reference!!
Submitted: 2001-07-05 10:54 UTC Modified: 2001-07-06 09:16 UTC
From: nassar at wpi dot edu Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 4.0.6 OS: Debian GNU/Linux (woody)
Private report: No CVE-ID: None
 [2001-07-05 10:54 UTC] nassar at wpi dot edu
When objects that contain objects that are referenced
elsewhere, they are not correctly dereferenced, and strange
side effects result

class Foo{
  var $a;
  function Foo($value)
    {
      $this->set($value);
    }
  function set($value)
    {
      $this->a = $value;
    }
  function get()
    {
      return $this->a;
    }
}
class Bar{
  var $a;
  function Bar($value)
    {
      $this->a = new Foo($value);
    }
  function set($value)
    {
      $this->a->set($value);
    }
  function get()
    {
      return $this->a->get();
    }
  function share($other)
    {
      $this->a = & $other->a;
    }
}

//Objects are initialized
$obj = new Bar(1);
$obj2 = new Bar(2);

//$obj and $obj2 both contain an internal reference to the
//same Foo object, with a value of 2
$obj->share($obj2);

//$obj2 now references a new Bar object with a new
//Foo object containing a value of 3
$obj2 = new Bar(3);

//$obj2 should be a copy of $obj1 and contain a new
//Foo object with a value of 2
$obj2 = $obj;

//Somehow, this also changes the value in $obj2
$obj->set(4);

//In a sane world, this outputs 2
//In reality, we get a 4
echo $obj2->get();

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2001-07-05 15:05 UTC] brianlmoon@php.net
This is expected behavior.  You are assuming that the object you had in $obj2 should be gone when you copy $obj to that var.  That is not the case.  It only changes what $obj2 points to.  Take this case:

$var=3;
$var2=&$var;
unset($var);
echo $var2;

$var2 is still 3.  The reference is gone but not the value of the var.  That is what makes references nice.

Brian.
 [2001-07-05 15:48 UTC] nassar at wpi dot edu
I think you misunderstood me. I'm not assuming that the
object in $obj2 should be gone after I copy something else
to this object. I AM assuming that the object in $obj is
that same object as was in $obj2 and that the object in
$obj2 is now a different object.

The issue is that the = operator does not create a complete
copy of the object referenced by $obj.  It instead creates
an object containing an object that is referenced by both
$obj and $obj2.

Maybe this will make it easier to see:

If you change "$obj2 = $obj;" to "$obj3 = $obj;" and "echo
$obj2->get();" to "echo $obj3->get();" in my code, you still
get the same results.

If you comment out "$obj->share($obj2);" the code returns 1,
which is what you would expect.

If this is the expected behavior, then it is not clearly
documented. If that is the case, this bug should probably be
changed to a documentation bug, and this example should be
added to the documentation with a detailed explanation.

 [2001-07-05 18:02 UTC] brianlmoon@php.net
But, the object that you referenced in the share() call is still in existence.  And the reference to that object is still good.  All obj1 has is a reference to something in its a var.  It copies that reference to the new object.  I don't see where a copy should have been made here.

Are you wanting PHP to make a new reference to a new piece of data?

 [2001-07-06 09:16 UTC] nassar at wpi dot edu
Yes.  PHP probably should make a new reference to a new
piece of data in this case.  It would seem to make more
sense to assign everything by value, since according to the
manual the assignment operator "really means that the the
left operand gets set to the value of the expression on the
right"

The current behavior is inconsistent. If $a is a variable
inside an object and I set $a by value, the = operator
copies it by value, but if I set $a by reference, the =
operator copies the reference.  Outside of an object, = will
copy a variable by value no matter how it is set.

In other words, "references" are treated like a different
data type in this case.  However, the programmer has no way
of determining this type(as far as I can tell).

If this behavior isn't changed, it should at least be
carefully documented, and there should be some way to
determine whether or not a variable is a reference variable.

For now, this will copy entirely by value:
$a = unserialize(serialize($b));

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 10:01:26 2024 UTC