深入解析PHP的引用计数机制

 更新时间:2013年06月14日 15:25:37   作者:  
本篇文章是对PHP中的引用计数机制进行了详细的分析介绍,需要的朋友参考下

PHP的变量声明并赋值后,变量名存在符号表中,而值和类信息存在zval中,zval中包含四个变量,is_ref,refcount,value,type,zval源码如下

复制代码 代码如下:

struct _zval_struct { 
    /* Variable information */ 
    zvalue_value value;     /* value */ 
    zend_uint refcount__gc; 
    zend_uchar type;    /* active type */ 
    zend_uchar is_ref__gc; 
};

refcount表示value地址与其相同的zval共有多少个,refcount=0时,zval被销毁
is_ref表示一个zval是否被引用,有“0”和“1”两种状态

此处分析一下什么时候zval会被复制或者开辟新的内存空间呢
1.当is_ref=0,且refcount>1时,如果改变某个指向该zval的变量的值,会生成新zval,原zval的refcount--,例如:$a=1;$b=$a;$b=2;,zval将被复制,也就是说原先ab指向同一个zval,后来b会使用新开辟的zval

2.当is_ref=0,且refcount>1时,如果将zval赋值给某个引用变量,那么用来赋值和变量和被赋值的变量会使用同一个原zval,而其他指向原zval的变量将会指向一个新复制的zval,且refcount会被重新计算,例如:$a=1;$b=$a;$c=$a;$d=&$a;,此时ad使用原zval,bc使用新复制出来的zval

3.当is_ref=1,且refcount>1时,如果将zval复制给某个非引用变量,该非引用变量会使用一个新复制的zval,元zval的refcount不变,例如:$a=1;$b=&$a;$c=$a,那么ab使用原zval,而c使用新复制的zval
type表示该zval的值类型,宏定义如下

复制代码 代码如下:

#define IS_NULL     0 
#define IS_LONG     1 
#define IS_DOUBLE   2 
#define IS_BOOL     3 
#define IS_ARRAY    4 
#define IS_OBJECT   5 
#define IS_STRING   6 
#define IS_RESOURCE 7 
#define IS_CONSTANT 8 
#define IS_CONSTANT_ARRAY   9

value表示该zval的值,他也是个共同体,代码如下
复制代码 代码如下:

typedef union _zvalue_value { 
    long lval;                  /* long value */ 
    double dval;                /* double value */ 
    struct { 
        char *val; 
        int len; 
    } str; 
    HashTable *ht;              /* hash table value */ 
    zend_object_value obj; 
} zvalue_value;

现在你知道php是如何类型变换的了,因为他的值存的其实是个可以代表任何类型的结构体,而具体的取值则根据type来决定是用共同体里的哪个变量来存值的

见下面的例子1
复制代码 代码如下:

.-----------
$a = 1;
$b = $a;
$c = $a;
.-----------
$d = &$a;
.-----------
$a = 2;
.-----------
$b = null;

查看refcount,is_ref,zval的变化
执行完第一部分后来看看输出
1-----------------------------
a:(refcount=3, is_ref=0),int 1
b:(refcount=3, is_ref=0),int 1
c:(refcount=3, is_ref=0),int 1
可以看出来a,b,c使用同一个zval
再看执行完第二部分的
2----------------------------
a:(refcount=2, is_ref=1),int 1
b:(refcount=2, is_ref=0),int 1
c:(refcount=2, is_ref=0),int 1
d:(refcount=2, is_ref=1),int 1
注意此时a,d在一起了,他们使用同一个zval,而bc使用一个新生成的zval,同时重新计算两个zval的refcount和is_ref
3----------------------------
a:(refcount=2, is_ref=1),int 2
b:(refcount=2, is_ref=0),int 1
c:(refcount=2, is_ref=0),int 1
d:(refcount=2, is_ref=1),int 2
可以知道ad这两个is_ref=1的好基友的值是同时改变的
4----------------------------
a:(refcount=2, is_ref=1),int 2
b:(refcount=1, is_ref=0),null
c:(refcount=1, is_ref=0),int 1
d:(refcount=2, is_ref=1),int 2
bc由于他们的zval的is_ref=0,所以他们不是好基友,他们的值不会同时改变,于是bc的zval再次分裂,b = null c = 1

相关文章

  • PHP中基本HTTP认证技巧分析

    PHP中基本HTTP认证技巧分析

    这篇文章主要介绍了PHP中基本HTTP认证技巧,实例分析了HTTP身份验证的原理与实现方法,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • PHP new static 和 new self详解

    PHP new static 和 new self详解

    使用 self:: 或者 __CLASS__ 对当前类的静态引用,取决于定义当前方法所在的类:使用 static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为“静态绑定”,因为它可以用于(但不限于)静态方法的调用。
    2017-02-02
  • php+ajax简单实现全选删除的方法

    php+ajax简单实现全选删除的方法

    这篇文章主要介绍了php+ajax简单实现全选删除的方法,结合实例形式分析了html+js前台全选及通过ajax与后台php交互实现批量删除的具体操作步骤与相关技巧,需要的朋友可以参考下
    2016-12-12
  • PHP反射基础知识回顾

    PHP反射基础知识回顾

    这篇文章主要介绍了PHP 反射的相关资料,帮助大家回顾和理解PHP的相关知识,感兴趣的朋友可以了解下
    2020-09-09
  • php邮件发送功能实现详解

    php邮件发送功能实现详解

    随着企业化的管理越来越规范,各种项目管理系统中,都需要加入到邮件实时通知功能,所以在项目中如何整合发邮件功能,其实也是很重要的一点。本文为大家介绍了PHP实现邮件实时通知功能的示例代码,需要的可以参考一下
    2022-09-09
  • PHP判断变量是否为0的方法

    PHP判断变量是否为0的方法

    这篇文章主要介绍了PHP判断变量是否为0的方法,需要的朋友可以参考下
    2014-02-02
  • php array_unique之后json_encode需要注意

    php array_unique之后json_encode需要注意

    php array_unique之后json_encode需要注意的地方,需要的朋友可以参考下。
    2011-01-01
  • 解析PHP留言本模块主要功能的函数说明(代码可实现)

    解析PHP留言本模块主要功能的函数说明(代码可实现)

    本篇文章是对PHP留言本中主要的函数以及代码进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • PHP栈的定义、入栈出栈方法及基于堆栈实现的计算器完整实例

    PHP栈的定义、入栈出栈方法及基于堆栈实现的计算器完整实例

    这篇文章主要介绍了PHP栈的定义、入栈出栈方法及基于堆栈实现的计算器,结合实例形式较为详细的分析了php定义与使用栈的基本方法,并结合完整实例形式给出了php基于堆栈实现高级计算器功能的相关操作技巧,需要的朋友可以参考下
    2017-11-11
  • 删除数组元素实用的PHP数组函数

    删除数组元素实用的PHP数组函数

    php之从数组中删除空白的元素(包括只有空白字符的元素)将一个二维数组转换为 hashmap
    2008-08-08

最新评论