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

<?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
LVL 1
rgb192Asked:
Who is Participating?
 
Dan CraciunConnect With a Mentor IT ConsultantCommented:
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
 
Ray PaseurCommented:
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
 
rgb192Author Commented:
<?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
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
Ray PaseurCommented:
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
 
Dan CraciunIT ConsultantCommented:
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
 
Dan CraciunIT ConsultantCommented:
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
 
rgb192Author Commented:
Ok. In current output what is (person) #1 (4) and (person) #3 (4)
0
 
Dan CraciunIT ConsultantCommented:
Those are instances no 1 and respectively no 3 of the class Person and each one has 4 properties/class variables.
0
 
rgb192Author Commented:
I did var_dump 1,2
Output is #1,3
0
 
Dan CraciunIT ConsultantCommented:
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
 
rgb192Author Commented:
#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
 
rgb192Author Commented:
so clone is copy in var_dump
thanks
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.