小而巧的zval
zval 是一个结构体,其中包含三个联合体(共同体):value、u1、u2;vaule8 字节,u1 和 u2 都是 4 个字节,正好 8 字节对其,所以 zval 的大小是 16 字节。
zval 用 16 字节可以表示 PHP 中的任意一个变量。
如何表示的呢?
line84 typedef struct _zval_struct zval;
为_zval_struct 这个结构体定义别名为 zval, ctrl + ] 跳转到 line121 查看_zval_struct:
1 | struct _zval_struct { |
然后定位 zend_value, ctrl+]跳转:
1 | typedef union _zend_value { |
接下来我们详细说明一下 zval 的结构: 显然, 它是一个结构体,包含三个值, 其类型都是联合体。
先看 value 的这个联合体 zend_value, 包含 14 个值, 经过 tags 的 ctrl+]跳转,我们发现:
zend_long 是 int64_t 的别名, 而 int64_t 又是__int64 的别名(关于__int64 可以查看笔记: 备忘/bit B(byte) KB.md)。
zend_refcounted 是_zend_refcounted 的别名,而_zend_refcounted 是一个结构体,其中只有一个值 gc,gc 是 zend_refcounted_h 类型的数据,而 zend_refcounted_h 是一个结构体:
1
2
3
4
5
6
7
8
9
10
11
12typedef struct _zend_refcounted_h {
uint32_t refcount; /* reference counter 32-bit */
union {
struct {
ZEND_ENDIAN_LOHI_3(
zend_uchar type,
zend_uchar flags, /* used for strings & objects */
uint16_t gc_info) /* keeps GC root number (or 0) and color */
} v;
uint32_t type_info;
} u;
} zend_refcounted_h;uint32_t 是 unsigned int 的别名。refcount 表示。。。,u 这个联合体中包含一个结构体 v 和一个 32 位正整型 type_info。
zend_uchar 是 unsigned char 的别名。
。。。未完待续
str 是指针,zend_string 是_zend_string 的别名
1
2
3
4
5
6struct _zend_string {
zend_refcounted_h gc;
zend_ulong h; /* hash value */
size_t len;
char val[1];
};gc 和垃圾回收有关。zend_ulong 是 uint32_t 的别名,表示 hash 值,防止冲突。
关于 size_t:
size_t 是一些 C/C++标准在 stddef.h 中定义的。这个类型足以用来表示对象的大小。size_t 的真实类型与操作系统有关。
在 32 位架构中被普遍定义为:typedef unsigned int size_t;
而在 64 位架构中被定义为:typedef unsigned long size_t;
为什么有时候不用 int,而是用 size_type 或者 size_t: 与 int 固定四个字节不同有所不同,size_t 的取值 range 是目标平台下最大可能的数组尺寸,一些平台下 size_t 的范围小于 int 的正数范围,又或者大于 unsigned int. 使用 Int 既有可能浪费,又有可能范围不够大。
len 用来储存字符串的长度。
val 是一个柔性数组,用来储存字符串。
arr 是指针,zend_array 是_zend_array 的别名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21struct _zend_array {
zend_refcounted_h 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;
Bucket *arData;
uint32_t nNumUsed;
uint32_t nNumOfElements;
uint32_t nTableSize;
uint32_t nInternalPointer;
zend_long nNextFreeElement;
dtor_func_t pDestructor;
};gc 与垃圾回收有关。
联合体 v。。。
。。。未完待续
obj 是指针,zend_object 是_zend_object 的别名
1
2
3
4
5
6
7
8struct _zend_object {
zend_refcounted_h gc;
uint32_t handle; // TODO: may be removed ???
zend_class_entry *ce;
const zend_object_handlers *handlers;
HashTable *properties;
zval properties_table[1];
};。。。未完待续
res 是指针,zend_resource 是_zend_resource 的别名
1
2
3
4
5
6struct _zend_resource {
zend_refcounted_h gc;
int handle; // TODO: may be removed ???
int type;
void *ptr;
};。。。未完待续
ref 是指针,zend_reference 是_zend_reference 的别名
1
2
3
4struct _zend_reference {
zend_refcounted_h gc;
zval val;
};。。。未完待续
ast 是指针,zend_ast_ref 是_zend_ast_ref 的别名
1
2
3
4struct _zend_ast_ref {
zend_refcounted_h gc;
zend_ast *ast;
};zend_ast 是_zend_ast 的别名
1
2
3
4
5
6
7
8
9typedef uint16_t zend_ast_kind;
typedef uint16_t zend_ast_attr;
struct _zend_ast {
zend_ast_kind kind; /* Type of the node (ZEND_AST_* enum constant) */
zend_ast_attr attr; /* Additional attribute, use depending on node type */
uint32_t lineno; /* Line number */
zend_ast *child[1]; /* Array of children (using struct hack) */
};。。。未完待续
zv 是指针
。。。未完待续
ptr 是指针
。。。未完待续
ce 是指针,zend_class_entry 是_zend_class_entry 的别名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63struct _zend_class_entry {
char type;
zend_string *name;
struct _zend_class_entry *parent;
int refcount;
uint32_t ce_flags;
int default_properties_count;
int default_static_members_count;
zval *default_properties_table;
zval *default_static_members_table;
zval *static_members_table;
HashTable function_table;
HashTable properties_info;
HashTable constants_table;
union _zend_function *constructor;
union _zend_function *destructor;
union _zend_function *clone;
union _zend_function *__get;
union _zend_function *__set;
union _zend_function *__unset;
union _zend_function *__isset;
union _zend_function *__call;
union _zend_function *__callstatic;
union _zend_function *__tostring;
union _zend_function *__debugInfo;
union _zend_function *serialize_func;
union _zend_function *unserialize_func;
zend_class_iterator_funcs iterator_funcs;
/* handlers */
zend_object* (*create_object)(zend_class_entry *class_type);
zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref);
int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type); /* a class implements this interface */
union _zend_function *(*get_static_method)(zend_class_entry *ce, zend_string* method);
/* serializer callbacks */
int (*serialize)(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data);
int (*unserialize)(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data);
uint32_t num_interfaces;
uint32_t num_traits;
zend_class_entry **interfaces;
zend_class_entry **traits;
zend_trait_alias **trait_aliases;
zend_trait_precedence **trait_precedences;
union {
struct {
zend_string *filename;
uint32_t line_start;
uint32_t line_end;
zend_string *doc_comment;
} user;
struct {
const struct _zend_function_entry *builtin_functions;
struct _zend_module_entry *module;
} internal;
} info;
};。。。未完待续
func 是指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19union _zend_function {
zend_uchar type; /* MUST be the first element of this struct! */
uint32_t quick_arg_flags;
struct {
zend_uchar type; /* never used */
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
uint32_t fn_flags;
zend_string *function_name;
zend_class_entry *scope;
union _zend_function *prototype;
uint32_t num_args;
uint32_t required_num_args;
zend_arg_info *arg_info;
} common;
zend_op_array op_array;
zend_internal_function internal_function;
};。。。未完待续
ww 结构体
综上可以看出,value 中存储的是变量内容,接下来我们看两个联合体 u1 和 u2。
1 | union { |
u1 中有一个结构体 v 和一个 32 位整型 type_info,这个 type_info 的作用就是获取 v 的值。这么写是一个小技巧。
zend_uchar 是 unsigned char 的别名,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
以上,整型就是 IS_LONG。
。。。未完待续
1 | union { |
u2 中的 next 用来解决数组中的冲突。