当我浏览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"
}
如果
,第三种情况也不应该为NULL新变量将访问与分配的对象相同的实例
否则,似乎$ assigned是按值传递的,如果第一个启动器($ instance)设置为NULL并且$ assigned没有更改其值,则不是引用。
答案 0 :(得分:0)
包含对象的变量实际上只包含对象引用。将每个实例化对象视为生活在幕后某个对象池中的变量,以及一个变量,只需要对象#3&#34;,引用等对象。
如果通过=
将此对象引用分配给另一个变量,则会生成此引用的副本。现在有两个变量包含&#34;对象#3&#34;的副本,它显然指的是同一个对象
使用=&
通过引用分配使得两个变量指向相同的引用,因此任何更改该引用的内容(如用null
覆盖它)都将影响这两个变量。该对象仍然在幕后继续存在,另一个持有另一个引用的变量不受影响。
答案 1 :(得分:0)
更新:修改了图表和解释,以反映更准确的内幕情况。
在计算机语言中,变量被命名为用于存储值的内存位置。在编译语言中,变量的名称通常在编译时消失;它们只是程序员的语言辅助工具。解释型语言保留变量名称,因为它们在运行时需要它们。
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
指向SimpleClass
类型的同一对象$instance
;使用$instance->var
或$assigned->var
访问对象的属性是一回事,因为它们都指向SimpleClass
类型的同一个实例; $reference = & $instance;
将新名称($reference
)添加到由名称$instance
标识的内存位置(变量); $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
,则会发生同样的情况(变量和对象数据都将无法访问,并且将被释放)。
答案 2 :(得分:0)
首先: -
用于垃圾收集的PHP用户参考计数方案,意味着每次将对象变量分配给另一个时,您将该计数器增加1,并且每当变量超出范围时,计数器将减少1
第二: - (通过参考传递变量)
$ a = 5; //认为$ a的内存地址是25,或者我们可以说“$ a”是一个指向位置25的指针,所以每当我们在其中分配somethig或将其与其他地方相关联时,我们就会获取该值的值这个变量的位置,
与
相同$ b = 10; //可能是内部存储器地址是26
但重要的是:
$ a = 10; //内存地址25 $ b =&amp; $ a; // $ b的内存地址也是25
所以,如果我写$ a = 11;所以$ b的值也会改变,因为它们是同一个内存位置的名称所以当我改变一个时它会影响其他内存位置,
现在谈谈这个问题: -
$instance = new SimpleClass();
这里有一个对象在内存中创建,我们可以在地址'x_address'上将其命名为'x',一个变量也创建名称$ instance,其位置为'instance_address',其中包含值'x_adderss',而Refrence表如下所示: -
参考表: -
object | refrence_count | memory_address
| |
'x' | 1 | 'x_address'
和变量堆栈看起来像这样: -
Stack: -
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'
因为现在有两个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'
注意没有参考_count增加,因为那个指向某个位置的变量,换句话说我们可以说现在我们可以指向位置 - &gt; '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'
所以$ assign仍指向内存中的对象,
当我们写这样的时候: -
$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
谢谢:) {抱歉英语不好,我不是英语母语者}