phpvariable-assignmentphp4assignment-operator

Why is the PHP assignment operator acting as an assignment by reference in this case?


I have some code that appears to behave differently between PHP 4 and PHP 5. This code below:

class CFoo
{
    var $arr;

    function CFoo()
    {
        $this->arr = array();
    }

    function AddToArray($i)
    {
        $this->arr[] = $i;
    }

    function DoStuffOnFoo()
    {
        for ($i = 0; $i < 10; ++$i)
        {
            $foo2 = new CFoo();
            $foo2 = $this;          // I expect this to copy, therefore
                                    // resetting back to the original $this
            $foo2->AddToArray($i);
            echo "Foo2:\n";
            print_r($foo2);
            echo "This:\n";
            print_r($this);
        }
    }
}

$foo1 = new CFoo();
$foo1->DoStuffOnFoo();

Previously, in PHP 4, the assignment of $foo2 above would reset $foo2 back to the value that $this was originally set at. In this case, I would expect it to be set to a CFoo with an empty $arr member. However, the assignment of $foo2 to $this is acting as an assignment by reference. Foo2 is acting as an alias to this. Therefore when I call "AddToArray" on foo2, $this's $arr is also being appended to. So when I go to reassign foo2 back to this, instead of getting the initial value of this, I get essentially a self assignment.

Has this behavior changed in PHP 5? What can I do to force foo2 to make a copy of this?


Solution

  • The object-oriented part of PHP has been hugely overhauled in PHP 5. Objects are now passed (not exactly but almost) as references. See http://docs.php.net/clone.

    Example:

    $x1 = new StdClass;
    $x1->a = 'x1a';
    
    $x2 = $x1;
    $y = clone $x1;
    
    // Performing operations on x2 affects x1 / same underlying object
    $x2->a = 'x2A';
    $x2->b = 'x2B';
    
    // y is a clone / changes do not affect x1
    $y->b = 'yB';
    
    echo 'x1: '; print_r($x1);
    echo 'y:'; print_r($y);
    

    prints

    x1: stdClass Object
    (
        [a] => x2A
        [b] => x2B
    )
    y:stdClass Object
    (
        [a] => x1a
        [b] => yB
    )