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;
在前两句执行之后,内存结构如下图