PHP7 引用计数 读书笔记
每个 PHP 变量存在一个加 "zval" 的变量容器中. 一个 zval 变量容器, 除了包含变量的类型和值, 还包括两个字节的额外信息.
1.is_ref : 是一个 bool 值, 用来标识这个变量是否属于引用集合. 通过这个字节, PHP 引擎才能把普通变量和引用变量区分开来, 由于 PHP 允许用户通过 & 来自定义引用, zval 变量容器中还有一个内部引用计数机制, 来优化内存使用.
2.refcount, 用来表示指向这个 zval 变量容器的变量 (也称为符号 symbol) 个数. 所有的符号存在一个符号表中, 其中每个符号都有作用域, 那些主脚本和每个函数或者方法也都有作用域.
接下来我们通过几个例子来帮助大家理解.(以下代码是在 Linux+php7.1 环境下)
1. 生成一个新的 zval 容器<?PHP
$a='new string';
xdebug_debug_zval('a');
输出结果如下:
从结果可以看出 refount = 0,is_ref=0 那怎么理解这个输出结果呢?
(1)is_ref = 0 信息很容易理解,$a 不是一个引用变量自然就是 0
(2)refount 的值怎么也是 0, 因为我们知道在 php7 中对于简单的数据类型, 比如整型, 字符串, 浮点型等简单类型的值是直接存储在 zval 结构里面.
如果把变量 a 赋值给多个变量会怎样?<?PHP
$a="new string";
$c=$b=$a;
xdebug_debug_zval('a');
输出结果如下:
发现 refcount 的值还是 0, 三个变量共用 1 个 zval 结构, 没有存符号表. 下面我们再给看下变量被引用后的情况:<?PHP
$a="new string";
$b=&$a;
$c=&$b;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
xdebug_debug_zval('c');
输出结果如下:
我们发现三个变量的 refount 和 is_ref 都相同, 那我们来解释下:
1. 当变量被引用后, 原来的 zval 结构会发生变化, PHP 会新增一个_zend_reference 结构, 这个结构会根据值得类型不同而不同.struct_zend_reference{
zend_refcounted_h gc;
zval val;
}
我们来看下 PHP 的具体操作:
(1)PHP 会申请一个 zend_reference 结构
(2)将 zval_reference.value 指向原来的 zval_struct.value
(3)zval_struct.value 的数据类型修改为 zend_refrence
(4)将 zval_struct.value 指向刚刚申请并初始化的 zend_reference
(5)为新变量申请 zval_struct 结构, 将他的 value 指向刚刚创建的 zend_reference
来源: http://www.bubuko.com/infodetail-3382348.html