php源码学习

php7中的zval结构体

2019-03-21  本文已影响0人  尤旭

php7中的zval结构体对比php5优化了很多,一个zval只占用16字节的空间,php7中的zval的结构体如下

struct _zval_struct {
    zend_value        value;            /* value */
    union {
        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    type,         /* active type */
                zend_uchar    type_flags,
                zend_uchar    const_flags,
                zend_uchar    reserved)     /* call info for EX(This) */
        } v;
        uint32_t type_info;
    } u1;
    union {
        uint32_t     next;                 /* hash collision chain */
        uint32_t     cache_slot;           /* literal cache slot */
        uint32_t     lineno;               /* line number (for ast nodes) */
        uint32_t     num_args;             /* arguments number for EX(This) */
        uint32_t     fe_pos;               /* foreach position */
        uint32_t     fe_iter_idx;          /* foreach iterator index */
        uint32_t     access_flags;         /* class constant access flags */
        uint32_t     property_guard;       /* single property guard */
        uint32_t     extra;                /* not further specified */
    } u2;
};

其中value的结构体占用了8个字节,这里面存储的就是zval中的value值的地方。

typedef union _zend_value {
    zend_long         lval;             /* long value */
        //整形
    double            dval;             /* double value */
    //浮点型
        zend_refcounted  *counted;
        //引用计数
    zend_string      *str;
        //字符串类型
    zend_array       *arr;
        //数组类型
    zend_object      *obj;
        //对象类型
    zend_resource    *res;
        //资源类型
    zend_reference   *ref;
        //引用类型
    zend_ast_ref     *ast;
        //抽象语法树
    zval             *zv;
        //zval类型
    void             *ptr;
        //指针类型
    zend_class_entry *ce;
        //class类型
    zend_function    *func;
        //funciton类型
    struct {
        uint32_t w1;
        uint32_t w2;
    } ww;
} zend_value;

其中针对php的各种类型增加了相应的结构体。
在zval结构体中,还有u1和u2,这两个字段记录了其他信息,比较关注的就是u1当中的type是用来标识这个zval的类型。type_info是对应变量的特有标记。
u1中的type类型对应关系为

/* regular data types */
#define IS_UNDEF                    0
#define IS_NULL                     1
#define IS_FALSE                    2
#define IS_TRUE                     3
#define IS_LONG                     4
#define IS_DOUBLE                   5
#define IS_STRING                   6
#define IS_ARRAY                    7
#define IS_OBJECT                   8
#define IS_RESOURCE                 9
#define IS_REFERENCE                10

/* constant expressions */
#define IS_CONSTANT                 11
#define IS_CONSTANT_AST             12

/* fake types */
#define _IS_BOOL                    13
#define IS_CALLABLE                 14
#define IS_ITERABLE                 19
#define IS_VOID                     18

/* internal types */
#define IS_INDIRECT                 15
#define IS_PTR                      17
#define _IS_ERROR                   20

用以标识zval数据类型。
比方说 我们php代码中定义一个$a = 1;

<?php
$a = 1;
echo $a;

我们用gdb来实际看下这个变量对应的结构体,在ZEND_ECHO_SPEC_CV_HANDLER打断点来查看。

1553151577345.jpg
其中可以看到打印出来的zval中u1.type为4,4代表IS_LONG类型,这是种简单类型,所以这个值被直接存储到了lval中了。
那么现在如果我们unset了这个$a变量,在来看看这个结构体。
<?php
$a = 1;
unset($a);
echo $a;
WX20190321-150605.png
可以看到这个时候的会把u1.type标识为0,0代表的是IS_UNDEF标记为未使用类型。待之后的垃圾回收机制来收回即可。
现在在来看一个字符串类型,字符串类型在php7中不是一个简单数据类型,他的value值会存储在value.str当中,我们这时候定义如下php代码
<?php
$a = 'a';
echo $a;

在来gdb看下这个zval结构

str1.png
这时候我们打印出来这个value.str看到他是一个zend_string类型的数据
str2.png

这个zend_string结构体在php源码中的定义是这样的

struct _zend_string {
    zend_refcounted_h gc;
    zend_ulong        h;                /* hash value */
    size_t            len;
    char              val[1];
};

我们具体看下他的数值。

str3.png
gc是处理垃圾回收的,h是冗余了一个hash值,是为了在数组操作中避免对于hash值的重复计算,len表示字符串的长度,val就是字符串的值。这里的结构体定义的char val[1]是一种柔性数组的应用,这样我们可以直接打印出来这个值
str4.png
这就是php7中的字符串通过zval中的str指向到了zend_string结构体。
上一篇 下一篇

猜你喜欢

热点阅读