zval结构中有以下两个成员变量用于引用计数器:
改变$a的值时,发现refcount的值变回1,所有这时候变量$a和$b 指向不同的内存块,这就是写时复制。就是两个指向同一内存块的变量,当其中一个变量的发生变化,才会另外创建一个内存块去保存新的值。
写时复制也是一种引用,只不过这种引用会受到变量值的改变而破坏罢了。
显式引用情况:
在PHP内核中通过以下代码判断是否复制变量:
is_ref:BOOL值,标识变量是否是引用集合写时复制:就是当变量的值改变时才进行内存的复制。
refcount:计算指向引用集合的变量个数
执行结果:<?php
$a = "this a test ";
xdebug_debug_zval('a');
$b = $a;
xdebug_debug_zval('a');
$a = "changed the test value";
xdebug_debug_zval('a');
当$a的值赋给变量$b时,变量$a的refcount增加1,所以这时候变量$a跟变量$b是指向同一内存块的;a:
(refcount=1, is_ref=0),string 'this a test ' (length=12) a:(refcount=2, is_ref=0),string 'this a test ' (length=12) a:(refcount=1, is_ref=0),string 'changed the test value' (length=22)
改变$a的值时,发现refcount的值变回1,所有这时候变量$a和$b 指向不同的内存块,这就是写时复制。就是两个指向同一内存块的变量,当其中一个变量的发生变化,才会另外创建一个内存块去保存新的值。
写时复制也是一种引用,只不过这种引用会受到变量值的改变而破坏罢了。
显式引用情况:
执行结果:<?php
$a = 1;
xdebug_debug_zval('a');
$b = & $a;
xdebug_debug_zval('a');
$b += 5;
xdebug_debug_zval('a');
is_ref字段等于1,表示此变量被引用。refcount也相应+1a:
(refcount=1, is_ref=0),int 1 a:(refcount=2, is_ref=1),int 1 a:(refcount=2, is_ref=1),int 6
在PHP内核中通过以下代码判断是否复制变量:
当变量被引用,或者引用计数器小于2时会直接返回变量的指针(直接返回变量的实体,而不复制变量的值)。当修改一个被引用变量的值时,所有引用他的变量其值也会被修改,因为他们指向同一个zval容器。if ((*varval->is_ref || (*varval)->refcount<2)) {
return *varval;
}