Web Analytics Made Easy -
StatCounter Unclear copy/referencs mix - CodingForum

Announcement

Collapse
No announcement yet.

Unclear copy/referencs mix

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unclear copy/referencs mix

    Try to execute following code: why the container object has been duplicated while the contained one has been referenced? How can I avoid this (doing a full copy of the original?)


    class CObject
    {
    var $subobj;
    var $value;
    function report() { return $this->value; }
    }

    $first = new CObject;
    $first->value = "First object";
    echo '$first->value = "'. $first->report(). '"<br>';

    $first->content = new CObject;
    $first->content->value = "Contained in the first object";
    echo '$first->content->value = "'. $first->content->report(). '"<br>';

    /////////////////
    $second = $first;
    /////////////////
    echo '<br>After assignment:<br><br>';

    $second->value = "Second object";
    echo '$second->value = "'. $second->report(). '"<br>';

    $second->content->value = "Contained in the second object";
    echo '$second->content->value = "'. $second->content->report(). '"<br>';

    echo '<br>while<br><br> $first->value = "'. $first->report(). '"<br>';

    $first->report();
    echo '<br><b>BUT!</b>: $first->content->value = "'. $first->content->report(). '"...WHY???<br>';

  • #2
    I have no idea.

    What do you want to have happen? Did you want them to be the same object, or two different objects?

    I would have thought that with your assignment, you would have merely copied a reference to your first object. Thus making any changes to the second object should have been reflected in the first object.

    If you were hoping for a copy, try this link:
    Generate the perfect name for your business, company, or brand. Domain and logo included!


    Good luck,
    Sadiq.

    Comment


    • #3
      When you use the "=" assignment operator on object, it makes a copy. But only a shallow copy. This means that if the copied object contains values that are references, the references will turn up in the copy and not the values of that referenced objects.

      If you need to do a deep copy, you have to do it on your own. Here's an example function that you can use. Of course, should the internal objects contain further references, these aren't deep copied, but you could recursively descend the internal structure and copy those objects as well. However, beware of cyclic references.

      PHP Code:
      class CObject
      {
          var 
      $subobj;
          var 
      $value;
          
          function 
      CObject() {
          
          }
          
          function 
      report() { 
              return 
      $this->value
          }
          
          function 
      copy() {
              
      $copyObj =& new CObject();
              foreach (
      get_object_vars($this) as $attr => $value) {
                  
      $copyObj->$attr $value;
              }
              return 
      $copyObj;
          }

      @sad69: Default behaviour in PHP 4 is to return a copy on assignment, unless you do it with the " =& " operator. PHP 5 will fix this, eh, rather uncommon feature.
      De gustibus non est disputandum.

      Comment


      • #4
        ahhh, thanks for clearing that up mordred. I'm a native Java programmer so I guess I just made that assumption..

        Although I believe you even more since I know that when you want to pass a variable by reference to a method, you have to put a '&' before the variable name (in the method signature...).

        One thing I have never seen though is that ->content-> thing. What is it? What is it used for? I tried to do search for it, but I didn't really find anything.

        Cheers,
        Sadiq.

        Comment


        • #5
          Originally posted by sad69
          ahhh, thanks for clearing that up mordred. I'm a native Java programmer so I guess I just made that assumption..
          This assumption is the same I would make, given that all other languages I know beside PHP pass objects implicitly as references, or to be more exact, as in the case of Java by passing references (object handles) by value. JavaScript behaves similar. PHP is the one which is different, IMO worse by doing this implicit copies.

          One thing I have never seen though is that ->content-> thing. What is it? What is it used for? I tried to do search for it, but I didn't really find anything.
          You're thinking in Java again.
          PHP is dynamically typed, unlike Java. You can add attributes to objects at runtime. That's what the OP was doing in this line:

          PHP Code:
          $first->content = new CObject
          The object stored in $first gets a new attribute, which points to a CObject. If it helps, think of PHP objects as associative arrays, where you can add keys/properties whenever it suits you.

          Not that I would recommend it, better nail down the object's interface by using the "var" statements and refrain from adding/deleting properties by the rest of your script.
          De gustibus non est disputandum.

          Comment


          • #6
            Oh I get it.. I think

            So content is just an attribute, like value, but it wasn't declared in the class?

            It is sort of a cool ability to be able to add attributes to an object I guess.. but then this new attribute would be specific to THAT object, not to the whole class... right?

            It does make sense to me, just took a few minutes after reading your answer. Thanks a lot mordred!

            Sadiq.

            Comment


            • #7
              Technically, if I do:

              PHP Code:
              $first->content = new CObject;
              ...
              $second $first
              I don't make any by-reference assignment, so the copy should be full qualified; more, if you rewrite the same, stripping out the functions from the classes, it works fine (PHP4.3.1). Can we maybe speak of a PHP's bug?

              Comment


              • #8
                I don't understand. Which functions should one strip where and why did you say it worked after that? You can try to file a bug on bugs.php.net, but unless you specify what exactly you meant with your last sentences, you're most certainly getting an RTFM answer to your bug report. AFAIK and as your previous sample script shows, PHP makes shallow copies of your objects. The comments in the specific manual sections say the same.
                De gustibus non est disputandum.

                Comment


                • #9
                  Following code has the same assignment sequence of the precedent, bu it works differently. I find no reasons for this.

                  PHP Code:
                  class CObject
                  {
                      var 
                  $subobj;
                      var 
                  $value;
                  //    function report() { return $this->value; }
                  }

                  $first = new CObject;
                  $first->value "First object";
                  echo 
                  '$first->value = "'$first->value'"<br>';

                  $first->content = new CObject;
                  $first->content->value "Contained in the first object";
                  echo 
                  '$first->content->value = "'$first->content->value'"<br>';

                  /////////////////
                  $second $first;
                  /////////////////
                  echo '<br>After assignment:<br><br>';

                  $second->value "Second object";
                  echo 
                  '$second->value = "'$second->value'"<br>';

                  $second->content->value "Contained in the second object";
                  echo 
                  '$second->content->value = "'$second->content->value'"<br>';

                  echo 
                  '<br>while<br><br> $first->value = "'$first->value'"<br>';

                  echo 
                  '<br><b>AND!</b>: $first->content->value = "'$first->content->value'"<br>'

                  Comment


                  • #10
                    This is indeed strange. It seems that after calling a method on a contained object, it gets changed to a reference. You can try it with this code, whenever you see the "&" in front of "object", it means that it's a reference.

                    PHP Code:
                    class CObject
                    {
                        var 
                    $subobj;
                        var 
                    $value;
                        
                        function 
                    report() {    
                            return 
                    $this->value
                        }
                    }
                    $first = new CObject();

                    $first->content = new CObject;
                    $first->content->value "Contained in the first object";

                    echo 
                    $first->content->report(); // comment this out to see the effect

                    $second $first;

                    echo 
                    '<pre>';
                    var_dump($first$second);
                    echo 
                    '</pre>'
                    I read somewhere that PHP objects really are in fact associative arrays. This could serve as an explanation, that the type gets changed from object by value to reference object by reference after a method gets called. But since objects without any methods aren't that useful, I can only advice you force them to be references by using "&", so you don't have to deal with quirks like this.

                    Whether this is a bug or not... dunno. Try your look and file a bug report. Perhaps they left something out of the documentation.
                    De gustibus non est disputandum.

                    Comment

                    Working...
                    X