PHP7.2中的zval

  • 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;
};
  • _zval_struct结构体由三部分组成, value是一个zend_value联合体,u1, u2是联合体,u1和u1分别占用4个字节。

  • 接着看zend_value联合体:

typedef union _zend_value {
    zend_long         lval;      // 整形
    double            dval;             // 浮点型
    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;  // 类
    zend_function    *func;  // 函数
    struct {
        uint32_t w1;
        uint32_t w2;
    } ww;  
} zend_value;
  • zend_value联合体可以表示整形丶浮点型等php中的类型, 甚至可以指向一个zval, 但同时只能表示其中一种类型,其占用8个字节。

  • _zval_struct结构体zend_val,u1,u2 8字节对齐, 所以总共占用16字节。

  • php虽然是弱类型语言,写代码不需要定义其类型,在底层实现的时候还是要区分类型的,底层实现做了类型转换的事情,且类型可以隐式包含了变量长度。

  • 在_zval_struct结构体中的u1中包含了一个结构体v, 其中:

    • zend_uchar 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
  • zend_uchar type_flags对应变量类型特有的标记, 可以表示常量丶可被复制的类型丶需要引用计数的类型:
/* zval.u1.v.type_flags */
#define IS_TYPE_CONSTANT            (1<<0)   // 常量
#define IS_TYPE_REFCOUNTED          (1<<2)  // 引用
#define IS_TYPE_COPYABLE            (1<<4)  // 可复制类型
  • zend_uchar const_flags是常量类型的标记。

  • zend_uchar reserved是保留字段。

  • _zval_struct中u2中的字段解析:

    • next字段用于解决哈希冲突。
    • cache_slot用于运行时缓存。
    • lineno记录php代码在哪一行,用于抽象语法树。
    • num_args记录函数的参数个数
    • fe_pos 记录foreach时的位置
    • fe_iter_idx 也是用于foreach,代表游标。
    • access_flags 用于类里边,表示访问修饰符。
    • property_guard 用于防止类中魔术方法的循环引用。
  • zval是由三个联合体所组成的,根据u1中的type来取zend_value中对应的值, 如type是long,那么直接取zend_value中的lval值。
  • zval可以表示PHP中的所有变量,PHP变量使用上是弱类型的,但底层实现是区分类型的。
发布了60 篇原创文章 · 获赞 0 · 访问量 1440

猜你喜欢

转载自blog.csdn.net/ClassmateLin/article/details/104324569
今日推荐