本文翻译自Nikita的文章,水平有限,如有错误,欢迎指正查看原文
受篇幅限制,这篇文章将分为两个部分。本部分会讲解PHP5和PHP7在zval结构体的差异,同时也会讨论引用的实现。第二部分会深入探究一些数据类型如string和对象的实现。
PHP5中zval结构体的定义如下:
typedef struct _zval_struct { zvalue_value value; zend_uint refcount__gc; zend_uchar type; zend_uchar is_ref__gc; } zval;
可以看到,zval由value、type和一些额外的__gc信息组成。__gc与垃圾回收相关,我们稍后讨论。value是一个共用体,可以存储y一个zval各种可能的值。
typedef union _zvalue_value { long lval; // For booleans, integers and resources double dval; // For floating point numbers struct { // For strings char *val; int len; } str; HashTable *ht; // For arrays zend_object_value obj; // For objects zend_ast *ast; // For constant expressions } zvalue_value;
C语言中,共用体的尺寸与它最大的成员尺寸相同,在某一时刻只能有一个成员处于活动状态。共用体所有的成员都存储在相同的内存,根据你访问的成员不同,内容会被解释成不同的类型。以上面的共用体为例,如果访问lval,值将被解释为一个有符号整型;而访问dval将被解释成双精度浮点型。以此类推。
为了弄清结构体中哪个成员处于活动状态,zval会存储一个整型type来标识具体的数据类型。
#define IS_NULL 0 /* Doesn't use value */ #define IS_LONG 1 /* Uses lval */ #define IS_DOUBLE 2 /* Uses dval */ #define IS_BOOL 3 /* Uses lval with values 0 and 1 */ #define IS_ARRAY 4 /* Uses ht */ #define IS_OBJECT 5 /* Uses obj */ #define IS_STRING 6 /* Uses str */ #define IS_RESOURCE 7 /* Uses lval, which is the resource ID */ /* Special types used for late-binding of constants */ #define IS_CONSTANT 8 #define IS_CONSTANT_AST 9