美文网首页php源码学习
php7中的zval结构体

php7中的zval结构体

作者: 尤旭 | 来源:发表于2019-03-21 15:20 被阅读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结构体。

    相关文章

      网友评论

        本文标题:php7中的zval结构体

        本文链接:https://www.haomeiwen.com/subject/ddnqvqtx.html