<?php
$
var
= "laruence";
$var_dup = $
var
;
$
var
= 1;
?>
很明显在这段代码执行以后,
$var_dup 的值应该还是”laruence”, 那么这又是怎么实现的呢?
这就是
PHP 的 copy on write 机制:
PHP 在修改一个变量以前,会首先查看这个变量的 refcount,如果 refcount 大于 1,PHP 就
会执行一个分离的例程,
对于上面的代码,当执行到第三行的时候,PHP 发现$
var
指向的
zval 的 refcount 大于 1,那么 PHP 就会复制一个新的 zval 出来,将原 zval 的 refcount 减 1,
并修改
symbol_table,使得$
var
和
$var_dup 分离(Separation)。这个机制就是所谓的 copy on
write(写时复制)。
上代码测试:
代码如下
:
<?php
$
var
= "laruence";
$var_dup = $
var
;
$
var
= 1;
debug_zval_dump($
var
);
debug_zval_dump($var_dup);
?>
输出:
long(1) refcount(2)
string(8) "laruence" refcount(2
现在我们知道,当使用变量复制的时候
,PHP 内部并不是真正的复制,而是采用指向相同
的结构来尽量节约开销。那么,对于
PHP 中的引用,那又是如何实现呢?
代码如下
:
<?php
$
var
= "laruence";
$var_ref = &$
var
;
$var_ref = 1;
?>
这段代码结束以后,
$
var
也会被间接的修改为
1,这个过程称作(change on write:写时改变)。
那么
ZE 是怎么知道,这次的复制是不需要 Separation 的呢?
这个时候就要用到
zval 中的 is_ref 字段了:
对于上面的代码,当第二行执行以后,
$
var
所代表的
zval 的 refcount 变为 2,并且同时置
is_ref 为 1。
到第三行的时候,
PHP 先检查 var_ref 代表的 zval 的 is_ref 字段,如果为 1,则不分离,大
体逻辑示意如下: