PHP 类 - 将启动的类分配给新变量


PHP Class - assigning initiated class to a new variable

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

将已创建的类实例分配给新变量时,新变量将访问与分配的对象相同的实例。

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

<?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"
}

如果 3 种情况不应该也是 NULL

新变量将访问与分配的对象相同的实例

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

First :-

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

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

$a = 5; 考虑 $a 的内存地址是 25,或者我们可以说"$a"是一个指向位置 25 的指针,所以每次我们在其中分配 somethig 或将其辅助到其他时,我们都在获取这个变量的位置的值,

$b = 10; 内部存储器地址可能为26

但重要的是:

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

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

现在谈谈这个问题:-

$instance = new SimpleClass();  

这里一个在内存中创建的对象,我们可以在地址"x_address"上将其命名为"x",并且一个变量也创建名称$instance其位置为"instance_address",其中包含值"x_adderss",引用表如下所示:-

参考表 :-

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 个变量引用了该对象,所以只有当两个对象都超出范围时,这个对象才会垃圾

下一条声明

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

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

下一条声明 :

$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

谢谢:){对不起,英语很弱,我的母语不是英语 }

包含对象的变量实际上只包含一个对象引用。将每个实例化的对象都想象成存在于幕后某个对象的池中,而变量只是保存类似"object#3"的东西,这是对该对象的引用

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

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

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

PHP 将简单类型(bool、integer、float、string)的值存储在变量中;它有不同的存储对象的方式:分配一个单独的内存块来存储对象数据,变量保存指向对象数据的引用/指针(内存中存储对象数据的地址)。

对象

赋值不会复制对象数据;它只是将数据的地址复制到新变量中。为了复制对象的数据,必须使用如下所示的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 中存储对它的引用(其内存地址);
  • $assigned = $instance;将存储在变量$instance中的值(即对对象的引用)复制到新的变量$assigned中; 这意味着$assigned指向与$instance相同的类型SimpleClass对象; 使用 $instance->var$assigned->var 访问对象的属性是一回事,因为它们都指向 SimpleClass 类型的同一实例;
  • $reference = & $instance; 在由名称 $instance 标识的内存位置(变量)中添加一个新名称 ($reference);
  • $duplicate = clone $instance;$instance = new SimpleClass();类似,但新创建的对象不是通过调用其构造函数来初始化的; 相反,$instance引用的对象的数据被复制到新对象中,然后调用其方法__clone()(如果存在);
  • $instance = NULL; 会将变量 $instance 的内容替换为 NULL(停止指向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未设置时也会发生同样的情况(变量和对象数据都变得不可访问,它们将被释放)。