深入理解PHP笔记 (二)

一、PHP变量在内核中的实现

PHP的变量在内核中是以zval结构体来实现的,保存在zend/zend.h文件中

struct _zval_struct {
    zvalue_value value; /* 变量的值 */
    zend_uint refcount__gc;
    zend_uchar type;    /* 变量当前的数据类型 */
    zend_uchar is_ref__gc;
};
typedef struct _zval_struct zval;

//在Zend/zend_types.h里定义的:
typedef unsigned int zend_uint;
typedef unsigned char zend_uchar;

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变量的引用计数
如果我们创建了两个相同的变量,比如:

<?php
$a = 'Hello World';
$b = $a;
unset($a);
我们检查变量$a和$b,会发现a和b都保存了只想内存中“hello world”的地址,查看一下最上面的zval结构体,有四个变量val,type,refcount_gc,isref_gc,前两个变量都知道什么意思,现在我们要用到后面两个变量了。当变量刚被创建的时候,refcount_gc就是1,当这个变量赋给其他变量的时候,refcount_gc就变为2。当unset掉这个变量的时候,就减一,说明还有其他变量还在用着这个值。

写时复写机制
还有一种情况

$a = 1;
$b = $a;
$b += 5;
在第二行的时候,和刚才上面介绍的情况是一样的,给b赋值的时候,refcount加1,但是到了第三行a和b还要共用一个内存地址吗?不是,这时候会检查refcount是否大于一,如果是的话会复制出来一份专属于b的zval

change on write
再来一种情况
$a = 1;
$b = &$a;
$b += 5;
当运行到第二行的时候,稍微会有些改变,refcount会继续加一变为2,同时is_ref也会变成一(原来默认为0),到第三行的时候会判断is_ref是否为1,或者是否小于2,如果是则直接返回原来的zval
if ((*varval)->is_ref || (*varval)->refcount < 2) {
    return *varval;
} 
Separation Anxiety
最后一种情况
$a = 1;
$b = $a;
$c = &$a; 
如果一种语言既有复制,又有引用的话,内核是怎么运作的呢?在这种情况下,变量必须分开独立,$a和$c共用一个zval,$b自己拥有一个zval

你可能感兴趣的:(深入理解PHP笔记 (二))