background image

这就解释了为什么 PHP 能够支持关联数组了;其次,Resource 就是一个 long 值,它里面
存放的通常是个指针、一个内部数组的 index 或者其它什么只有创建者自己才知道的东西,
可以将其视作一个 handle。

1.1.2 引用计数
引用计数在垃圾收集、内存池以及字符串等地方应用广泛,Zend 就实现了典型的引用计
数。多个 PHP 变量可以通过引用计数机制来共享同一份 zval,zval 中剩余的两个成员
is_ref 和 refcount 就用来支持这种共享。
很明显,refcount 用于计数,当增减引用时,这个值也相应的递增和递减,一旦减到零,
Zend 就会回收该 zval。
那么 is_ref 呢?
1.1.3 zval 状态
在 PHP

——

中,变量有两种

引用和非引用的,它们在 Zend 中都是采用引用计数的方式存

储的。对于非引用型变量,要求变量间互不相干,修改一个变量时,不能影响到其他变量,
采用 Copy-On-Write

——

机制即可解决这种冲突

当试图写入一个变量时,Zend 若发现该

变量指向的 zval 被多个变量共享,则为其复制一份 refcount 为 1 的 zval,并递减原 zval 的
refcount

,这个过程称为 zval

分离 。然而,对于引用型变量,其要求和非引用型相反,引

用赋值的变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。
可见,有必要指出当前 zval 的状态,以分别应对这两种情况,is_ref 就是这个目的,它指
出了当前所有指向该 zval

——

的变量是否是采用引用赋值的

要么全是引用,要么全不是。

此时再修改一个变量,只有当发现其 zval 的 is_ref 为 0,即非引用时,Zend 才会执行
Copy-On-Write。
1.1.4 zval 状态切换
当在一个 zval 上进行的所有赋值操作都是引用或者都是非引用时,一个 is_ref 就足够应付
了。然而,世界总不会那么美好,PHP 无法对用户进行这种限制,当我们混合使用引用和
非引用赋值时,就必须要进行特别处理了。
情况 I、看如下 PHP 代码:

代码如下:
 
<?php

$a

 = 1;

$b

 = 

$a

;

$c

 = 

$b

;

$d

 = &

$c

// 在一堆非引用赋值中,插入一个引用

?>

这段代码首先进行了一次初始化,这将创建一个新的 zval,is_ref=0, refcount=1,并将 a
指向这个 zval;之后是两次非引用赋值,正如前面所说,只要把 b 和 c 都指向 a 的 zval 即
可;最后一行是个引用赋值,需要 is_ref 为 1,但是 Zend 发现 c 指向的 zval 并不是引用型
的,于是为 c 创建单独的 zval,并同时将 d 指向该 zval。