简体   繁体   中英

PHP Class - assigning initiated class to a new variable

As I am going through PHP manual ( http://php.net/manual/en/language.oop5.basic.php ), I came across the following confusion:

When assigning an already created instance of a class to a new variable, the new variable will access the same instance as the object that was assigned.

And below manual contains the following example:

<?php

$instance = new SimpleClass();

$assigned   =  $instance;
$reference  =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

With output

NULL
NULL
object(SimpleClass)#1 (1) {
   ["var"]=>
     string(30) "$assigned will have this value"
}

Shouldn't 3rd case be also NULL if

the new variable will access the same instance as the object that was assigned

Otherwise it seems that $assigned is passed by value, not reference if the first initiator ($instance) was set to NULL and $assigned didn't change its value.

A variable that contains an object actually just contains an object reference . Think of every instantiated object as living in some pool of objects somewhere behind the scenes, and a variable just holding something like "object#3", a reference to the object.

If you assign this object reference to another variable via = , a copy of this reference is made. Now two variables hold a copy of "object#3", which obviously refers to the same object.
Assigning by reference using =& makes two variables point to the same reference, so anything changing that reference (like overwriting it with null ) will influence both variables. The object still continues to exist behind the scenes though, another variable holding another reference to it is not affected.

UPDATE: modified the diagram and the explanation to reflect more accurate what happens under the hood.

In computer languages, the variables are named memory locations that are used to store values. On compiled languages, the names of the variables usually vanish at the compile time; they are just language aids for the programmers. The interpreted languages keep the variable names because they need them at the runtime.

PHP stores the values of simple types (bool, integer, float, string) in variables; it has a different way to store the objects: a separate memory block is allocated to store the object data and the variable holds a reference/pointer to the object data (the address in memory where the object data is stored).

Object assignment does not duplicate the object data; it just copies the address of the data into a new variable. In order to duplicate an object's data, one must use the clone operator like this:
$duplicate = clone $instance;

The code:

$instance  = new SimpleClass();
$assigned  =  $instance;
$reference =& $instance;
$duplicate = clone $instance;
$number    = 123;

produces something like this in memory:

 $instance
 $reference
+----------------------+           +----------------------------+
| address of object #1 | --------> | SimpleClass object #1 data |
+----------------------+           +----------------------------+
                                                 ^
 $assigned                                       |
+----------------------+                         |
| address of object #1 | ------------------------+
+----------------------+

 $duplicate
+----------------------+           +----------------------------+
| address of object #2 | --------> | SimpleClass object #2 data |
+----------------------+           +----------------------------+

 $number
+------+
| 123  |
+------+

The rectangles are memory locations used to store data; some of them have names displayed above them (the variables), others do not (memory blocks that store the objects data).

How it works:

  • $instance = new SimpleClass(); allocate a block of memory to store a new object of type SimpleClass and store a reference to it (its memory address) in the variable $instance ;
  • $assigned = $instance; copies the value stored in variable $instance (ie the reference to the object) into the new variable $assigned ; this means $assigned points to the same object of type SimpleClass as $instance ; accessing the object's properties using $instance->var or $assigned->var is the same thing because they both point to the same instance of the SimpleClass type;
  • $reference = & $instance; adds a new name ( $reference ) to the memory location (variable) identified by name $instance ;
  • $duplicate = clone $instance; is similar with $instance = new SimpleClass(); but the newly created object is not initialized by calling its constructor; instead, the data of the object referenced by $instance is copied into the new object then its method __clone() is invoked, if exists;
  • $instance = NULL; will replace the content of variable $instance with NULL (stops pointing to the SimpleClass object #1) but it will not affect either $assigned (it's a different variable) or the SimpleClass object #1 itself; the object can still be accessed through variable $assigned ; $reference will have the same value as $instance because they are just names for the same memory location (that stores NULL now).

The data structures now looks like:

 $instance
 $reference
+-------------------+              +----------------------------+
| NULL              |              | SimpleClass object #1 data |
+-------------------+              +----------------------------+
                                                 ^
 $assigned                                       |
+----------------------+                         |
| address of object #1 | ------------------------+
+----------------------+

 $duplicate
+----------------------+           +----------------------------+
| address of object #2 | --------> | SimpleClass object #2 data |
+----------------------+           +----------------------------+

 $number
+------+
| 123  |
+------+

unset($instance); just removes the name $instance from the variable; because it still has another name ( $reference ) the variable still exists and it can be accessed and modified using its other name. When $reference is also unset the variable cannot be accessed any more and the memory it uses will be released on the next garbage collection cycle. The same happens when $assigned is unset (both the variable and the object data become inaccessible and they will be released).

First :-

PHP user refrence counting scheme for Garbage collection, mean every time when you assign a object variable to another you are increasing that counter by 1 and every time when a variable goes out of scope, counter will decrease by 1

Second :- ( passing variables by refrence )

$a = 5; // consider the memory address of $a is 25 or we can say that "$a" is a pointer that point to location 25, so every time when we assign somethig in it or assining it to other we are fetching the value of the location of this variable,

same as

$b = 10; // may be internally memory address is 26

but the important thing is :

$a = 10; // memory address 25 $b = &$a; // $b's memory address is also 25

so if i write $a = 11; so $b's value will also change became they are the name of the same memory location so when i change one it affect other also,,

Now talk about this problem :-

$instance = new SimpleClass();  

here a object create in memory, we can name it 'x' on address 'x_address' and a variable also create name $instance that's location is 'instance_address' that contain the value 'x_adderss' and Refrence table look like this :-

RefrenceTable :-

object   |   refrence_count   |   memory_address
         |                    |
 'x'     |      1             |      'x_address'

and Variable stack look like this :-

Stack :-

Variable_name    |      Variable_address      |     Variable_value
                 |                            |  
 instance        |      'instance_address'    |      'x_address'  

Now next statement

$assigned   =  $instance;

Variable Stack :-

Variable_name    |      Variable_address      |     Variable_value
                 |                            |  
 instance        |      'instance_address'    |      'x_address'  
 assigned        |      'assigned_address'    |      'x_address'

and

RefrenceTable :-

object   |   refrence_count   |   memory_address
         |                    |
 'x'     |      2             |      'x_address'

Because now 2 varialbe refrencing that object, so this object only will garbage when both will be goes out of scope

Next statement

$reference  = & $instance;   // One of the most important line

Variable Stack :-

Variable_name    |      Variable_address      |     Variable_value
                 |                            |  
 instance        |      'instance_address'    |      'x_address'  
 assigned        |      'assigned_address'    |      'x_address'
 refrence        |      'instance_address'    |      'x_address' // because pointing the same 
                                                                 // memory as instance 

RefrenceTable :-

object   |   refrence_count   |   memory_address
         |                    |
 'x'     |      2             |      'x_address'   

Notice no refrence _count increased, because that varialbe that point to some location,, In other words we can say that now we can point location -> 'instance_address' with 2 names

Next Statement :

$instance->var = '$assigned will have this value';  // Not so  some changed happend in 'x_address'

Next Statement :

$instance = null;  // one 

of the important line

Variable Stack :-

Variable_name    |      Variable_address      |     Variable_value
                 |                            |  
 instance        |      'instance_address'    |        NULL  
 assigned        |      'assigned_address'    |      'x_address'
 refrence        |      'instance_address'    |        NULL // because pointing the same 
                                                                 // memory as instance 

Because instance and refrenced point to same location, if we change one values second will automaticallye changed, so both become null 

But refrence_count of object 'x' will be decrease by 1

RefrenceTable :-

object   |   refrence_count   |   memory_address
         |                    |
 'x'     |      1             |      'x_address'   

so $assigned still point to object in memory,,

and when we will write like this :-

   $assigned = null;  

Then

Variable_name    |      Variable_address      |     Variable_value
                 |                            |  
 instance        |      'instance_address'    |        NULL  
 assigned        |      'assigned_address'    |        NULL
 refrence        |      'instance_address'    |        NULL // because pointing the same 
                                                                 // memory as instance 


object   |   refrence_count   |   memory_address
         |                    |
 'x'     |      0             |      'x_address'     // Marked for Garbe collection

Thanks :) { Sorry for weak english, im not a native english speaker }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM