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
打断点来查看。
其中可以看到打印出来的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结构
这时候我们打印出来这个
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];
};
我们具体看下他的数值。
gc是处理垃圾回收的,h是冗余了一个hash值,是为了在数组操作中避免对于hash值的重复计算,len表示字符串的长度,val就是字符串的值。这里的结构体定义的
char val[1]
是一种柔性数组的应用,这样我们可以直接打印出来这个值str4.png
这就是php7中的字符串通过zval中的
str
指向到了zend_string
结构体。
网友评论