当我阅读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
未设置时也会发生同样的情况(变量和对象数据都变得不可访问,它们将被释放)。