php内核学习-基本变量zval 和zend

    xiaoxiao2023-11-01  25

    1.zval是php变量底层定义的结构,一共16字节

    typedef struct _zval_struct zval; struct _zval_struct { zend_value value; union u1; union u2; };

    zval 的详细结构如下: zend_value 是一个联合体 它的大小是8个字节 u1 联合体 4个字节 u2 联合体 4个字节 共16字节

    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; //4个字节 //ZEND_ENDIAN_LOHI_4 定义 define ZEND_ENDIAN_LOHI_4(a, b, c, d) d; c; b; a; //typedef unsigned char zend_uchar; uint32_t type_info; //4个字节 } u1; union { uint32_t next; /* hash collision chain 用来解决哈希冲突问题,记录冲突的下一个元素位置*/ uint32_t cache_slot; /* literal cache slot 运行时缓存。在执行函数时会优先去缓存中查找,若缓存中没有,会在全局的function表中查找*/ uint32_t lineno; /* line number (for ast nodes) 文件执行的行号,应用在AST节点上 */ 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; }; 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;

    zend_uchar type /* active type */ type代表含义:

    #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

    struct array

    array的数据结构定义在zend_types.h中

    typedef struct _zend_array zend_array; typedef struct _zend_array HashTable; struct _zend_array { zend_refcounted_h gc; //gc 垃圾回收的信息 union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar flags, zend_uchar nApplyCount, zend_uchar nIteratorsCount, zend_uchar consistency) } v; uint32_t flags; } u; uint32_t nTableMask; //散列函数映射元素在arData数组中的下标 Bucket *arData; //存数组元素的头指针,存储的元素结构是Bucket类型的 uint32_t nNumUsed; //已经bucket的个数 uint32_t nNumOfElements; //数组实际存储的元素个数 uint32_t nTableSize; //数组的容量(大小) uint32_t nInternalPointer; zend_long nNextFreeElement; //下个可用的数值索引,eg:arr[]=1; arr['a']=2; arr[]=3; 则nNextFreeElement=2 dtor_func_t pDestructor; }; typedef struct _Bucket{ zval val; //存储具体的value zend_ulong h; //哈希值或者数值索引 zend_string *key; //存储元素的key }

    基本实现

    <?php $a['foo'] = 1; $a[] = 22; $a['s'] ='df'; $a['x'] = 4; echo $a; 33087 z = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); (gdb) n 33089 if (Z_TYPE_P(z) == IS_STRING) { (gdb) p z $25 = (zval *) 0x7ffff5a1e080 //数组的底层也是zval (gdb) p *z $26 = {value = {lval = 140737314694368, dval = 6.9533472278435683e-310, counted = 0x7ffff5a624e0, str = 0x7ffff5a624e0, arr = 0x7ffff5a624e0, obj = 0x7ffff5a624e0, res = 0x7ffff5a624e0, ref = 0x7ffff5a624e0, ast = 0x7ffff5a624e0, zv = 0x7ffff5a624e0, ptr = 0x7ffff5a624e0, ce = 0x7ffff5a624e0, func = 0x7ffff5a624e0, ww = { w1 = 4121306336, w2 = 32767}}, u1 = {v = {type = 7 '\a', type_flags = 20 '\024', const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 5127}, u2 = {next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0, property_guard = 0, extra = 0}} //u1.v.type=7 是数组类型 (gdb) p *z.value.arr $27 = {gc = {refcount = 1, u = {v = {type = 7 '\a', flags = 128 '\200', gc_info = 0}, type_info = 32775}}, u = {v = {flags = 26 '\032', nApplyCount = 0 '\000', nIteratorsCount = 0 '\000', consistency = 0 '\000'}, flags = 26}, nTableMask = 4294967288, arData = 0x7ffff5a68660, nNumUsed = 4, nNumOfElements = 4, nTableSize = 8, nInternalPointer = 0, nNextFreeElement = 1, pDestructor = 0x8c6f9c <_zval_ptr_dtor_wrapper>} //nTableSize = 8 标识$a中数组的容量是8, nNumUsed = 4, 已经用了4个 nNumOfElements = 4,实际用了4个, nNextFreeElement = 1,因为$a[]=22用掉一个,默认重0开始的。 (gdb) p z.value.arr.nTableMask $28 = 4294967288 (gdb)p (int32_t)z.value.arr.nTableMask 29 = -8 // nTableMask = -nTableSize (gdb) p z.value.arr.arData[0] $30 = {val = {value = {lval = 1, dval = 4.9406564584124654e-324, counted = 0x1, str = 0x1, arr = 0x1, obj = 0x1, res = 0x1, ref = 0x1, ast = 0x1, zv = 0x1, ptr = 0x1, ce = 0x1, func = 0x1, ww = {w1 = 1, w2 = 0}}, u1 = {v = { type = 4 '\004', type_flags = 0 '\000', const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 4}, u2 = {next = 4294967295, cache_slot = 4294967295, lineno = 4294967295, num_args = 4294967295, fe_pos = 4294967295, fe_iter_idx = 4294967295, access_flags = 4294967295, property_guard = 4294967295, extra = 4294967295}}, h = 9223372037048267657, key = 0x7ffff5a6db40} //取第0个元素 (gdb) p (int32_t)$30.h | $34 $36 = -7 // nindex = bucket.h | (int32_t)z.value.arr.nTableMask ,$a['foo'] 对应的值存储的索引下标是-7 (gdb) p ((uint32_t*)(z.value.arr.arData))[(int32_t)(-7)] $37 = 0 //算出的0是对应bucket的位置,与上边我们取的数组的下边一致 (gdb) p z.value.arr.arData[1] $39 = {val = {value = {lval = 22, dval = 1.0869444208507424e-322, counted = 0x16, str = 0x16, arr = 0x16, obj = 0x16, res = 0x16, ref = 0x16, ast = 0x16, zv = 0x16, ptr = 0x16, ce = 0x16, func = 0x16, ww = {w1 = 22, w2 = 0}}, u1 = {v = { type = 4 '\004', type_flags = 0 '\000', const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 4}, u2 = {next = 4294967295, cache_slot = 4294967295, lineno = 4294967295, num_args = 4294967295, fe_pos = 4294967295, fe_iter_idx = 4294967295, access_flags = 4294967295, property_guard = 4294967295, extra = 4294967295}}, h = 0, key = 0x0} (gdb) p (int32_t)$39.h | $34 $40 = -8 (gdb) p ((uint32_t*)(z.value.arr.arData))[(int32_t)(-8)] $41 = 2 // 2 不等于 上边的下标1,这时说明在数组中别的key和1这个位置映射的索引数组的位置冲突,这个时候去取z.value.arr.arData[2].u2.next,一次类推直到取到和上边的下标对应数值 (gdb) p z.value.arr.arData[2] $42 = {val = {value = {lval = 140737314741312, dval = 6.9533472301629101e-310, counted = 0x7ffff5a6dc40, str = 0x7ffff5a6dc40, arr = 0x7ffff5a6dc40, obj = 0x7ffff5a6dc40, res = 0x7ffff5a6dc40, ref = 0x7ffff5a6dc40, ast = 0x7ffff5a6dc40, zv = 0x7ffff5a6dc40, ptr = 0x7ffff5a6dc40, ce = 0x7ffff5a6dc40, func = 0x7ffff5a6dc40, ww = { w1 = 4121353280, w2 = 32767}}, u1 = {v = {type = 6 '\006', type_flags = 0 '\000', const_flags = 0 '\000', reserved = 0 '\000'}, type_info = 6}, u2 = {next = 1, cache_slot = 1, lineno = 1, num_args = 1, fe_pos = 1, fe_iter_idx = 1, access_flags = 1, property_guard = 1, extra = 1}}, h = 9223372036854953496, key = 0x1398fd0}
    最新回复(0)