background image

C 语言中,一种解决方案是采用指针,所有函数调用尽量传递指 针。的确很灵活高效,但
也很难维护

~指针可以说是 C 语言程序员心头的痛(当然也是福~^_^)。还有一种更高级更有

效的方法是采用引用计数

 (Reference counting)。

  在

PHP 中,也可以采用引用来解决这样的问题,但你见过采用在 PHP 中大量使用引用

的吗

?显然很少。

  在

PHP 内核中,Zval 的实现正是采用了引用计数的概念,说起引用计数就不得不谈到

copy-on-write 机制。这样前面谈到的 refcount 和 is_ref 就有作用了。
  

refcount:引用次数。在 zval 初始创建的时候就为 1。每增加一个引用,则 refcount ++。

  

is_ref:用于表示一个 zval 是否是引用状态。zval 初始化的情况下会是 0,表示不是引用。

  在

Zend/Zend.h 内部有一些关于 ZVAL 的宏定义,里面比较清晰的解析了引用计数的一

些规则,其中重点关注以下几个宏定义
  

#define INIT_PZVAL(z) \

  

(z)->refcount = 1; \

  

(z)->is_ref = 0;

  

#define SEPARATE_ZVAL_IF_NOT_REF(ppzv) \//非引用下的变量分离

  

if (!PZVAL_IS_REF(*ppzv)) { \

  

SEPARATE_ZVAL(ppzv); \

  

}

  

#define SEPARATE_ZVAL_TO_MAKE_IS_REF(ppzv) \//非引用下的变量分离,并且设置

引用
  

if (!PZVAL_IS_REF(*ppzv)) { \

  

SEPARATE_ZVAL(ppzv); \

  

(*(ppzv))->is_ref = 1; \

  

}

  

#define SEPARATE_ARG_IF_REF(varptr) \ //引用下的变量分离

  

if (PZVAL_IS_REF(varptr)) { \

  

zval *original_var = varptr; \

  

ALLOC_ZVAL(varptr); \

  

varptr->value = original_var->value; \

  

varptr->type = original_var->type; \

  

varptr->is_ref = 0; \

  

varptr->refcount = 1; \

  

zval_copy_ctor(varptr); \

  

} else { \

  

varptr->refcount++; \

  

}

  这里面谈到两个重要的概念:
  

1、非引用下的变量分离。

  非引用下的变量分离,是指在一堆非引用变量中插入引用的情况下,在

PHP 内部进行

的一种内存操作。以下面的列子来看:
  

$a = 1;

  

$b = $a;

  

$c = &$b;

  在前两句执行之后,内存结构如下图