?
Solved

I do not understand how a cloned object can edit the original object

Posted on 2014-04-08
12
Medium Priority
?
212 Views
Last Modified: 2014-04-16
<?php
class Account {
    public $balance;
    function __construct( $balance ) {
        $this->balance = $balance;
    }
    function display(){
      return $this->balance;
    }
}

class Person {
    private $name;
    private $age;
    private $id;
    public $account;

    function __construct( $name, $age, Account $account ) {
        $this->name = $name;
        $this->age  = $age;
        $this->account = $account;
    }

    function setId( $id ) {
        $this->id = $id;
    }

    function __clone() {
        $this->id   = 0;
    }
}

$person = new Person( "bob", 44, new Account( 200 ) );
$person->setId( 343 );
$person2 = clone $person;

// give $person some money
$person->account->balance += 10;
// $person2 sees the credit too
print $person2->account->balance;
echo '<br>person2: display: '.$person2->account->display();

// output:
// 210

echo '<br>';
// give $person2 some money
$person2->account->balance += 10;
// $person sees the credit too
print $person->account->balance;
echo '<br>person: display: '.$person->account->display();

?>

Open in new window


I understood the code with cloning

So I decided to add
// give $person2 some money
$person2->account->balance += 10;
// $person sees the credit too
print $person->account->balance;
echo '<br>person: display: '.$person->account->display();

but now I do not understand how a cloned object can edit the original object


this is the output:
210
person2: display: 210
220
person: display: 220
0
Comment
Question by:rgb192
  • 5
  • 5
  • 2
12 Comments
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 39987671
Are you suspicious of this?

   function __clone() {
        $this->id   = 0;
    }
This is one of those things that needs some attention to var_dump() so you can see the data.
0
 
LVL 1

Author Comment

by:rgb192
ID: 39987787
<?php
class Account {
    public $balance;
    function __construct( $balance ) {
        $this->balance = $balance;
    }
    function display(){
      return $this->balance;
    }
}

class Person {
    private $name;
    private $age;
    private $id;
    public $account;

    function __construct( $name, $age, Account $account ) {
        $this->name = $name;
        $this->age  = $age;
        $this->account = $account;
    }

    function setId( $id ) {
        $this->id = $id;
    }

    function __clone() {
        $this->id   = 0;
    }
}

$person = new Person( "bob", 44, new Account( 200 ) );
$person->setId( 343 );
$person2 = clone $person;

// give $person some money
$person->account->balance += 10;
// $person2 sees the credit too
print $person2->account->balance;
echo '<br>person2: display: '.$person2->account->display();

// output:
// 210

echo '<br><pre>';
var_dump($person);
var_dump($person2);
echo '</pre>';

echo '<br>';
// give $person2 some money
$person2->account->balance += 10;
// $person sees the credit too
print $person->account->balance;
echo '<br>person: display: '.$person->account->display();

echo '<br><pre>';
var_dump($person);
var_dump($person2);
echo '</pre>';

?>

Open in new window


210
person2: display: 210

object(Person)#1 (4) {
  ["name":"Person":private]=>
  string(3) "bob"
  ["age":"Person":private]=>
  int(44)
  ["id":"Person":private]=>
  int(343)
  ["account"]=>
  object(Account)#2 (1) {
    ["balance"]=>
    int(210)
  }
}
object(Person)#3 (4) {
  ["name":"Person":private]=>
  string(3) "bob"
  ["age":"Person":private]=>
  int(44)
  ["id":"Person":private]=>
  int(0)
  ["account"]=>
  object(Account)#2 (1) {
    ["balance"]=>
    int(210)
  }
}


220
person: display: 220

object(Person)#1 (4) {
  ["name":"Person":private]=>
  string(3) "bob"
  ["age":"Person":private]=>
  int(44)
  ["id":"Person":private]=>
  int(343)
  ["account"]=>
  object(Account)#2 (1) {
    ["balance"]=>
    int(220)
  }
}
object(Person)#3 (4) {
  ["name":"Person":private]=>
  string(3) "bob"
  ["age":"Person":private]=>
  int(44)
  ["id":"Person":private]=>
  int(0)
  ["account"]=>
  object(Account)#2 (1) {
    ["balance"]=>
    int(220)
  }
}

Open in new window



I notice in var_dump
$person is listed every time
and there is no $person2

is this because $person2 was formed using a clone
0
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 39988294
Sorry - I'll be out of town for a few days.  Hopefully one of the other Experts will pick this up.  Taxi is waiting now.  Good luck!
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 35

Expert Comment

by:Dan Craciun
ID: 39991274
In the var_dump you only see the class, and that is Person.

In php, clone creates a shallow copy, which means the cloned object's properties that are objects point to the properties of the original object.

Effectively clone by default does not clone included objects also.

The internal objects of the new object will be references to the same objects in memory as the internal objects of the original object that was cloned (it clones the reference).

If you want to change that, you use the __clone() method. Php calls that method after the clone is complete, so any properties you want to make unique to the clone have to be initialized in the __clone method.

HTH,
Dan
0
 
LVL 35

Expert Comment

by:Dan Craciun
ID: 39995184
OK, try no 2 :)

You've read about passing parameters by value and by reference, so the concepts should be clear.

In PHP, after you do $x = 1; $x will have the value 1.
If you do $obj = new Account(); $obj will be a reference to an instance of the class Account, or, in other words, $obj's value is a reference to Account.

When you use clone, PHP will create a new object and copy all the values of the cloned instance variables.

In your example, $person contains:
$name with the value: 'bob'
$age with the value: 44
$id with the value: 343
$account with the value: a reference to an instance of the class Account

After you use clone, PHP will create a new object ($person2) with brand new variables and give them the original's object values:
$name with the value: 'bob'
$age with the value: 44
$id with the value: 343
$account with the value: a reference to the same instance of the class Account
After finishing the copy, PHP will run __clone() and set $id to 0.

Looking at the above, you can see that after clone,
$person->account and $person2->account both have equal values, which means they both point to the same object.

If you want to avoid that, modify __clone() like this:
function __clone() {
        $this->id   = 0;
        $this->account = new Account(0)
    }

This will create a new instance of the Account class, and $person2->account will point to that new instance.

Please tell me if I wasn't clear enough.
0
 
LVL 1

Author Comment

by:rgb192
ID: 39996305
Ok. In current output what is (person) #1 (4) and (person) #3 (4)
0
 
LVL 35

Expert Comment

by:Dan Craciun
ID: 39996330
Those are instances no 1 and respectively no 3 of the class Person and each one has 4 properties/class variables.
0
 
LVL 1

Author Comment

by:rgb192
ID: 39996353
I did var_dump 1,2
Output is #1,3
0
 
LVL 35

Expert Comment

by:Dan Craciun
ID: 39996373
Yes, because the instances are numbered sequentially for all classes, not for each class.
So in your case:
#1: the first instance of class Person
#2: the first instance of class Account
#3: the second instance of class Person
0
 
LVL 1

Author Comment

by:rgb192
ID: 39997963
#1: the first instance of class Person
#2: the first instance of class Account
#3: the second instance of class Person

what about $person2
is $person2 an instance of class person
0
 
LVL 35

Accepted Solution

by:
Dan Craciun earned 2000 total points
ID: 39998189
Of course. If $person is an instance of the class Person, then it's clone will be a new instance of the same class.
0
 
LVL 1

Author Closing Comment

by:rgb192
ID: 40004793
so clone is copy in var_dump
thanks
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Password hashing is better than message digests or encryption, and you should be using it instead of message digests or encryption.  Find out why and how in this article, which supplements the original article on PHP Client Registration, Login, Logo…
This article discusses how to create an extensible mechanism for linked drop downs.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to dynamically set the form action using jQuery.
Suggested Courses

615 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question