深入PHP使用技巧之变量
但也很难维护~指针可以说是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; 在前两句执行之后,内存结构如下图
在第三句 $c = &$b;语句中则会执行“非引用下的变量分离。”,具体步骤是: 将b分离出来,同时把a对应的zval的refcount-1。 copy 出一个新的zval,并把zval的is_ref设置成1. 把C指向这个新的zval,同时refcount ++ 最终效果如下图:
2、引用下的变量分离。 引用下的变量分离,是指在一堆引用变量中进行一个非引用赋值操作,这个时候会直接执行copy内存的操作。 以下面的例子来说 $a = 1; $b = &$a; $c = $b; 在执行完前两行后,PHP中内存结构如下:
在第三句,则会执行“引用下的变量分离”也就是真正的copy,最终内存结构如下图
据此,基本上对PHP变量内部的一些原理比较清楚了,但还有一些需要注意点的: 1、PHP变量的引用计数特性,对于数组同样也存在。但注意,对于key则不生效。(具体在后面章节会分析到。) 2、PHP变量中的对象比较特殊,在PHP5之后,默认都是采用引用赋值的方式。具体实现可以参考Zend_objects.*系列代码。 3、对于分析PHP内部变量,推荐采用xdebug_debug_zval,而不要采用内置的debug_zval_dump。因为PHP内置的debug_zval_dump函数一方面无法处理is_ref,而且采用了引用的方式来处理,从而导致看到结果会有误解。 使用技巧结论 据此可以得出分析出不少结论: 1、在PHP开发中不推荐采用引 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |