本文对应的php版本7.4.3
下载地址:https://www.php.net/downloads
zval是什么
zval是表示php变量的数据结构
每个zval占用多大的空间
一共占16个字节,value占8字节,u1和u2都占4字节。
源码文件地址
php/include/php/Zend/zend_types.h文件
整体结构
struct _zval_struct {
zend_value value; /* value */
union {
struct {
ZEND_ENDIAN_LOHI_3(
zend_uchar type, /* active type */
zend_uchar type_flags,
union {
uint16_t extra; /* not further specified */
} u)
} v;
uint32_t type_info;
} u1;
union {
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* cache slot (for RECV_INIT) */
uint32_t opline_num; /* opline number (for FAST_CALL) */
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 constant_flags; /* constant flags */
uint32_t extra; /* not further specified */
} u2;
};
主要有value,u1,u2三大块,接下来我们来看下每块对应的结构以及都是做什么的。
value块解析
我们通过追源码发现zend_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;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
可以把它理解成类型的集合,你能用到的都在这里。
u1块解析
union {
struct {
ZEND_ENDIAN_LOHI_3(
zend_uchar type, /* active type */
zend_uchar type_flags,
union {
uint16_t extra; /* not further specified */
} u)
} v;
uint32_t type_info;
} u1;
u1.type:根据type去取value中对应的值,如果我的type是 7,那么他就会去value中去取zend_array,可选值如下
/* 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_AST 11
/* internal types */
#define IS_INDIRECT 13
#define IS_PTR 14
#define IS_ALIAS_PTR 15
#define _IS_ERROR 15
/* fake types used only for type hinting (Z_TYPE(zv) can not use them) */
#define _IS_BOOL 16
#define IS_CALLABLE 17
#define IS_ITERABLE 18
#define IS_VOID 19
#define _IS_NUMBER 20
u1.type_flags:对应变量类型特有的标记,比如说引用计数的类型、可能包含循环引用的类型等等,取值如下
/* zval.u1.v.type_flags */
#define IS_TYPE_REFCOUNTED (1<<0)
#define IS_TYPE_COLLECTABLE (1<<1)
u2块解析
union {
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* cache slot (for RECV_INIT) */
uint32_t opline_num; /* opline number (for FAST_CALL) */
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 constant_flags; /* constant flags */
uint32_t extra; /* not further specified */
} u2;
u2.next:用来解决hash冲突
u2.cache_slot:用来做运行时缓存
u2.lineno:标记是php的哪一行,一般用在抽象语法树
u2.num_arg:函数调用传入的参数个数
u2.fe_pos:foreach时候它的位置,我们每foreach一次。这个值就会加1
u2.fe_iter_idx:和上面的类似,也是在foreach时使用,代表游标的索引位置
u2.access_flags:用在类里面,比如说我们写代码的时候用到的private、public、protected类型标记就是用的这个字段
u2.property_guard:防止类中魔术方法的循环引用,get和set会用到
u2.constant_flags:常量类型的标记