PHP Class - 将启动的 class 分配给一个新变量

PHP Class - assigning initiated class to a new variable

在阅读 PHP 手册 (http://php.net/manual/en/language.oop5.basic.php) 时,我遇到了以下困惑:

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.

下面的手册包含以下示例:

<?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);
?>

有输出

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

如果

第三种情况不应该也是 NULL

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

否则 $assigned 似乎是按值传递的,如果第一个启动器 ($instance) 设置为 NULL 并且 $assigned 没有更改其值,则不是引用。

一个包含对象的变量实际上只包含一个对象引用。将每个实例化的对象想象成生活在幕后某处的某个对象池中,并且一个变量只包含 "object#3" 之类的东西,对象的 引用

如果您通过 = 将此对象引用分配给另一个变量,则会创建此引用的副本。现在两个变量持有 "object#3" 的副本,这显然指的是同一个对象。
使用 =& 通过引用赋值使两个变量指向同一个引用,因此任何改变该引用的东西(比如用 null 覆盖它)都会影响这两个变量。尽管该对象仍然继续存在于幕后,但另一个持有对它的引用的变量不受影响。

更新: 修改了图表和解释以更准确地反映引擎盖下发生的事情。

在计算机语言中,变量被命名为用于存储值的内存位置。在编译语言中,变量名通常在编译时消失;它们只是程序员的语言辅助工具。解释型语言保留变量名,因为它们在运行时需要它们。

PHP 将简单类型(bool、integer、float、string)的值存储在变量中;它有不同的方式来存储对象:分配一个单独的内存块来存储对象数据,并且变量持有一个 reference/pointer 到对象数据(存储对象数据的内存地址)。

对象分配不复制对象数据;它只是将数据的地址复制到一个新变量中。为了复制对象的数据,必须像这样使用 clone 运算符:
$duplicate = clone $instance;

代码:

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

在内存中产生这样的东西:

 $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  |
+------+

矩形是用于存储数据的内存位置;其中一些上面显示了名称(变量),其他则没有(存储对象数据的内存块)。

工作原理:

  • $instance = new SimpleClass();分配一块内存来存储一个新的SimpleClass类型的对象,并在变量$instance;[=78中存储对它的引用(它的内存地址) =]
  • $assigned = $instance;将存储在变量$instance中的值(即对对象的引用)复制到新变量$assigned中;这意味着 $assigned 指向与 $instance 类型相同的 SimpleClass 对象;使用 $instance->var$assigned->var 访问对象的属性是一回事,因为它们都指向 SimpleClass 类型的同一个实例;
  • $reference = & $instance; 将新名称 ($reference) 添加到由名称 $instance;
  • 标识的内存位置(变量)
  • $duplicate = clone $instance;$instance = new SimpleClass(); 类似,但新创建的对象不是通过调用其构造函数来初始化的;相反,$instance 引用的对象的数据被复制到新对象中,然后调用其方法 __clone()(如果存在);
  • $instance = NULL; 将用 NULL 替换变量 $instance 的内容(停止指向 SimpleClass 对象 #1)但它不会影响任何 $assigned (这是一个不同的变量)或 SimpleClass 对象 #1 本身;该对象仍然可以通过变量 $assigned 访问; $reference 将具有与 $instance 相同的值,因为它们只是相同内存位置的名称(现在存储 NULL)。

数据结构现在看起来像:

 $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); 只是从变量中删除名称 $instance;因为它还有另一个名字($reference),所以变量仍然存在,可以使用它的另一个名字访问和修改它。当 $reference 也被取消设置时,变量不能再被访问,它使用的内存将在下一个垃圾收集周期被释放。当 $assigned 未设置时也会发生同样的情况(变量和对象数据都变得不可访问,它们将被释放)。

第一个:-

PHP 垃圾收集的用户引用计数方案,意味着每次将对象变量分配给另一个对象时,计数器都会增加 1,每次变量超出范围时,计数器都会减少通过 1

第二:-(通过引用传递变量)

$a = 5; // 考虑 $a 的内存地址是 25 或者我们可以说“$a”是指向位置 25 的指针,所以每次我们在其中分配一些东西或将它分配给其他东西时,我们都在获取值这个变量的位置,

相同

$b = 10; // 可能是内部内存地址是 26

但重要的是:

$a = 10; //内存地址25 $b = &$a; // $b的内存地址也是25

所以如果我写 $a = 11;所以 $b 的值也会改变,因为它们是同一内存位置的名称,所以当我改变一个时,它也会影响其他,

现在说说这个问题:-

$instance = new SimpleClass();  

这里在内存中创建了一个对象,我们可以在地址 'x_address' 上将其命名为 'x' 并且变量也创建名称 $instance 其位置是 'instance_address' 包含值 'x_adderss' 和 Refrence table 看起来像这样:-

参考表:-

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

和变量堆栈看起来像这样:-

堆栈:-

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

现在下一条语句

$assigned   =  $instance;

变量堆栈:-

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

参考表:-

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

因为现在 2 varialbe 引用了那个对象,所以这个对象只有在两者都超出范围时才会成为垃圾

下一条语句

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

变量堆栈:-

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 

参考表:-

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

注意 refrence _count 没有增加,因为指向某个位置的变量,换句话说,我们现在可以指向位置 -> 'instance_address' 和 2 个名称

下一条语句:

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

下一条语句:

$instance = null;  // one 

重要的一行

变量堆栈:-

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 

但是对象'x'的refrence_count会减1

参考表:-

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

所以 $assigned 仍然指向内存中的对象,

我们什么时候会这样写:-

   $assigned = null;  

然后

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

谢谢 :) { 抱歉英语不好,我的母语不是英语}