Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 4 of 4
  1. #1
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts

    OOP cloning objects

    in php 5.3 i noticed that you have to use clone to copy an object as using the = operator will copy by reference. Why is this? what would happen if you use &
    e.g whats the differnece between
    PHP Code:
    $obj2 $obj
    $obj3 
    = &$obj;
    $obj4 = clone $obj
    You can not say you know how to do something, until you can teach it to someone else.

  • #2
    Regular Coder
    Join Date
    Jan 2012
    Posts
    134
    Thanks
    0
    Thanked 32 Times in 32 Posts
    Let's test:

    PHP Code:
    class test {
        public 
    $foo;
    }

    $test = new test();
    $test -> foo 1;
    echo 
    $test -> foo;

    $copy1 $test;
    $copy2 = &$test;
    $copy3 = clone $test;

    echo 
    '<hr>';
    $test -> foo 2;
    echo 
    $copy1 -> foo;
    echo 
    $copy2 -> foo;
    echo 
    $copy3 -> foo;

    echo 
    '<hr>';
    $copy1 -> foo 3;
    echo 
    $copy1 -> foo;
    echo 
    $copy2 -> foo;
    echo 
    $copy3 -> foo;

    echo 
    '<hr>';
    $copy2 -> foo 4;
    echo 
    $copy1 -> foo;
    echo 
    $copy2 -> foo;
    echo 
    $copy3 -> foo;

    echo 
    '<hr>';
    $copy3 -> foo 5;
    echo 
    $copy1 -> foo;
    echo 
    $copy2 -> foo;
    echo 
    $copy3 -> foo
    Run that code, and you'll see that the cloned object is the only one that is not "linked" to the original object.

  • Users who have thanked KuriosJon for this post:

    timgolding (02-15-2012)

  • #3
    Senior Coder timgolding's Avatar
    Join Date
    Aug 2006
    Location
    Southampton
    Posts
    1,519
    Thanks
    114
    Thanked 110 Times in 109 Posts
    So really theres no difference between
    PHP Code:
    $copy $test//and
    $copy = &$test
    when they designed this why didn't they keep the = construtor for making copies and the & for copying by reference as with all other data types. Or is all this to allow __clone to be called when cloning so you can run some additional code if need be?
    You can not say you know how to do something, until you can teach it to someone else.

  • #4
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,994
    Thanks
    4
    Thanked 2,662 Times in 2,631 Posts
    Typical OO rules specify that you are provided with either the original memory or a link to the original memory (as in PHP and Java). The reference is different, but they both dereference to the same memory space.
    Cloning is used to copy an object in its entirety to a new memory space. This includes all primitives and any reference to objects. So if you have a property that is an object, both the original and the clone will still share the same reference to the property and updates are reflected within both.
    Objects are not created with an assignment. They are created when new is called on the class.

    As for by reference, no they are different. Objects don't carry their memory pointers during assignment, they carry an object pointer which is simply a pointer to the memory location. Typical usage of the = &$obj will appear to function the same, but it is not and will not work in all situations:
    PHP Code:
    <?php

    class A
    {
        public 
    $inner;
        public function 
    __construct(B $inner)
        {
            
    $this->inner $inner;
        }
    }

    class 
    B
    {
        public 
    $desc;
        public function 
    __construct($desc "I'm the first B")
        {
            
    $this->desc $desc;
        }
    }

    $b = new B();
    $a = new A($b);
    $aCopy $a;
    $aRef = &$a;
    $aClone = clone $a;

    // These will all say I'm the first B
    print_r($a);
    print_r($aCopy);
    print_r($aRef);
    print_r($aClone);


    function 
    modifyBValue(A $in)
    {
        
    $in->inner->desc "Value change in " __FUNCTION__;
    }
    print 
    str_repeat('-'100) . PHP_EOL;
    modifyBValue($a);
    // These should now all indicate B value was changed in modifyBValue.
    print_r($a);
    print_r($aCopy);
    print_r($aRef);
    print_r($aClone);

    function 
    modifyB(A $in)
    {
        
    $in->inner = new B("Assigned in " __FUNCTION__);
    }
    print 
    str_repeat('-'100) . PHP_EOL;
    modifyB($a);
    // These should now all indicate B object was changed in modifyB
    print_r($a);
    print_r($aCopy);
    print_r($aRef);

    // This should still say it was modified in modifyBValue:
    print_r($aClone);

    function 
    modifyANonRef(A $in)
    {
        
    $in = new A(new B());
    }

    print 
    str_repeat('-'100) . PHP_EOL;
    modifyANonRef($a);
    // None of these will change:
    print_r($a);
    print_r($aCopy);
    print_r($aRef);
    print_r($aClone);


    // Here's where we see the difference in byref:
    function modifyA(&$in// <-- This requires the & in order to modify the original variable and NOT the object pointer (which would have no effect)
    {
        
    $in = new A(new B());
    }

    print 
    str_repeat('-'100) . PHP_EOL;
    modifyA($a); // or just a $a = new A(new B()) would work too
    // I'm the first B
    print_r($a);

    // Assigned in modifyB
    print_r($aCopy);

    // I'm the first B
    print_r($aRef);

    // Value change in modifyBValue
    print_r($aClone);
    So as you can see $aCopy = $a; and $aRef = &$a; do not actually do the same thing. There is limited situations for this, which would be the reassignment of a variable using a copy context in a function for example.
    This is why when we say objects in PHP are passed by reference it is NOT actually true, but in MOST situations it seems that way. Objects in PHP are passed by OBJECT reference.

    BTW, you can override __clone as well to perform a deep copy if you want. That would involve issuing a clone on the $inner in my example, which would make the $aClone never change to reflect that of $a.

  • Users who have thanked Fou-Lu for this post:

    timgolding (02-15-2012)


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •