当我们将NULL赋给$instance
时,为什么$assigned
不变为NULL ?当我们通过$instance->var
改变$var
的值时,$assigned
获得新的更新值。
class SimpleClass
{
// property declaration
public $var = 'a default value';
// method declaration
public function displayVar() {
echo $this->var;
}
}
$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"
}
基本知识
要理解发生了什么,你需要深入php的内部,看看内存是如何管理的。
在底层,值是这样表示的:
+--------------------+
| (type) {{ VALUE }} |
| refcount = a |
| isref = b |
+--------------------+
引用计数器a
计算指向该值的变量的数量。isref
标志显示该值是由值赋值(即$a = VALUE
)还是由引用赋值(即$a =& VALUE
)。
让我们假设如下情况:
+--------------------------+
$a ------------->| (int) 58 | $a = 58
| refcount = 1 ; isref = 0 |
+--------------------------+
如果你将$a
的值复制到$b
中,PHP只会增加refcount
的值以节省内存(即不存储两次相同的值):
+--------------------------+
$a -------+----->| (int) 58 | $b = $a
| | refcount = 2 ; isref = 0 |
| +--------------------------+
|
|
$b -------+
如果您将$b的值更改为其他值,则会创建一个新值并减少对58
的refcount:
+--------------------------+
$a ------------->| (int) 58 | $b = 'hello'
| refcount = 1 ; isref = 0 |
+--------------------------+
+--------------------------+
$a ------------->| (string) 'hello' |
| refcount = 1 ; isref = 0 |
+--------------------------+
在引用的情况下,isref
标志被设置为true
,并且更改会影响两个标识符:
+--------------------------+
$a -------+----->| (int) 58 | $b =& $a
| | refcount = 2 ; isref = 1 |
| +--------------------------+
|
|
$b -------+
.
+--------------------------+
$a -------+----->| (int) 21 | $b = 21
| | refcount = 2 ; isref = 1 |
| +--------------------------+
|
|
$b -------+
关于对象引用
你可以经常听到在PHP中,对象通过引用透明地传递。根据医生的说法,这并不完全正确。名称标识符$a
包含一个对象标识符,这就是函数之间传递的内容。我将在下面用一个类型为object
的整数来说明这个标识符,我不知道它到底是如何在底层完成的,但是解释是成立的;-)
不要混淆标识符,即变量名与对象标识符,即对象在内存中的编号。
+--------------------------+
$a ------------->| (object) 547654764237685 | $a = new FooBar();
| refcount = 1 ; isref = 0 |
+--------------------------+
在内存的其他地方,PHP存储了我们刚刚创建的标识符为547654764237685
的FooBar
实例。当您使用值(object) 547654764237685
时,PHP会自动检索该对象并允许您透明地使用它。
发生了什么?
让我们逐行检查你的代码。
首先创建一个新的SimpleClass
实例。
+--------------------------+
$instance ------>| (object) 547654764237685 | $instance = new SimpleClass();
| refcount = 1 ; isref = 0 |
+--------------------------+
然后给$assigned
赋值,即增加refcount
:
+--------------------------+
$instance ---+-->| (object) 547654764237685 | $assigned = $instance;
| | refcount = 2 ; isref = 0 |
| +--------------------------+
|
|
$assigned ---+
第三行引用$reference
到$instance
。因为值的refcount
大于1,而且它还不是一个引用(isref = 0
), PHP在内存中创建一个新的类似的值:
+--------------------------+
$instance ---+-->| (object) 547654764237685 | $reference =& $instance;
| | refcount = 2 ; isref = 1 |
| +--------------------------+
|
|
$reference --+
+--------------------------+
$assigned ------>| (object) 547654764237685 |
| refcount = 1 ; isref = 0 |
+--------------------------+
三个标识符$instance
、$assigned
和$reference
求值为完全相同的对象,因为对象标识符保持不变。但是,我们现在在内存中有两个不同的值。
这就是为什么调用$instance->var = '$assigned will have this value';
会影响$instance->var
、$assigned->var
和$reference->var
。
现在,当您将$instance
设置为null
时,因为$reference
引用相同的值,两者都受到影响:
+--------------------------+
$instance ---+-->| (NULL) | $instance = null;
| | refcount = 2 ; isref = 1 |
| +--------------------------+
|
|
$reference --+
+--------------------------+
$assigned ------>| (object) 547654764237685 |
| refcount = 1 ; isref = 0 |
+--------------------------+
$assigned
的对象引用不受影响,因为它是一个单独的值,因此$assigned
仍然调用该对象。
我认为这是因为在将其标识符赋为空值后,对象本身仍然是完整的。
当你设置一个对象的字段-它驻留在对象的内存部分,但是当你设置它的"指针"另一个值-它驻留在其他地方,所以对象本身仍然在那里,可以被另一个标识符(指针)引用。
这里有一个ref: php.net