浅谈PHP中的变量 zval变量容器 PHP引用计数器

PHP语言有一个特点就是资源共享,这一点在PHP的变量存储方式上也有体现。PHP的变量是一种弱类型,PHP是如何去实现变量的存储呢?

引用计数器

变量的C语言实现有两个重要的元素,一个是zvalue_value联合体,另一个是zval结构体

zvalue_value联合体的定义


typedef union _zvalue_value {  
    long lval;                  // 对应PHP中的integer boolean long resource
    double dval;                // 对应PHP中的float
    // 对应PHP中的string
    struct {  
             char *val;  
             int len;  
           } str;  
    HashTable *ht;              // 对应PHP中的array 
    zend_object_value obj;      // 对应PHP中的object
} zvalue_value;


PHP中的变量类型都被对应到联合体中某个变量,值得一提的是resource类型,被对应到long类型的原因是,php会有一个资源表,long里面存的是一个偏移量。


zval结构体的定义

struct _zval_struct {  
    // 变量实际的值
    zvalue_value value;       
    // 变量被引用的次数
    zend_uint refcount__gc;  
    // 变量的类型
    zend_uchar type;
    // 变量是否被引用,&$a  
    zend_uchar is_ref__gc;  
};


每个php变量都存在"zval"的变量容器中。如上所示,zval变量容器包含了变量的类型和值,另外还有两个字节的额外信息。第一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。通过这个字节,php引擎才能把普通变量和引用变量区分开来,由于php允许用户通过使用&来使用自定义引用,zval变量容器中还有一个内部引用计数机制,来优化内存使用。第二个额外字节是"refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。所有的符号存在一个符号表中,其中每个符号都有作用域(scope),那些主脚本(比如:通过浏览器请求的的脚本)和每个函数或者方法也都有作用域。

例如编写以下的代码


$a   =   "new string" ;
xdebug_debug_zval ( 'a' );
$b   =   $a ;
xdebug_debug_zval ( 'a' );
$c   =   $a ;
xdebug_debug_zval ( 'a' );
unset $b ,   $c  );
xdebug_debug_zval ( 'a' );
$d   =   & $a ;
xdebug_debug_zval ( 'a' );
?>


打印的结果应该为

a: (refcount=1, is_ref=0)='new string'
a: (refcount=2, is_ref=0)='new string'
a: (refcount=3, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'
 
  
a: (refcount=1, is_ref=1)='new string'

ref:http://www.php.net/manual/zh/features.gc.refcounting-basics.php




你可能感兴趣的:(php)