background image

<?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,则不分离,大

体逻辑示意如下: