每个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
原文:https://www.cnblogs.com/shuzhen2020/p/12196216.html