在PHP源码中一切数据类型都是zval,它的结构如下图:
zval: 定义在文件zend.h中
struct _zval_struct {
zvalue_value value;
zend_uint refcount;
zend_uchar type;/*值类型IS_**/
zend_uchar is_ref;
};
数据类型: 可以用Z_TYPE_PP或者Z_TYPE_P来查看zval是个,这些类型定义在zend.h中:
#define IS_NULL 0
#define IS_LONG 1
#define IS_DOUBLE 2
#define IS_BOOL 3
#define IS_ARRAY 4
#define IS_OBJECT 5
#define IS_STRING 6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY 9
zvalue_value的定义是:
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
HashTable的定义是
typedef struct _hashtable {
uint nTableSize;
uint nTableMask;
uint nNumOfElements;
ulong nNextFreeElement;
Bucket *pInternalPointer; /* Used for element traversal */
Bucket *pListHead;
Bucket *pListTail;
Bucket **arBuckets;
dtor_func_t pDestructor;
zend_bool persistent;
unsigned char nApplyCount;
zend_bool bApplyProtection;
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;
Bucket定义如下:
typedef struct bucket {
ulong h; /* Used for numeric indexing */
uint nKeyLength;
void *pData;
void *pDataPtr;
struct bucket *pListNext;
struct bucket *pListLast;
struct bucket *pNext;
struct bucket *pLast;
char arKey[1]; /* Must be last element */
} Bucket;
Copy On Write copy on write是一种在写内存的时候根据是否有引用来拷贝的机制,下例中当把a赋值给b后,a和b,它们都使用内存中的同一个zval,当给b重新赋值时 zend引擎知道refcount为2,这时会给b copy一份新的zval,在zend解析参数时的“/”也就时判断是否要进行分离(b相当于从a分离)
•is_ref为0
•这时修改其中一个,其它的值为原来的值
$a = 123;
$b = $a;
这时有$a和$b都如下($a和$b都引用相同的zval):
value.lval= 123
refcount= 2
type = IS_LONG
is_ref= 0
$b = 456;
这时的$a和$b如下(Zend要查看refcount的值,并且确保在它的值大于1时对之进行分离):
$a:
value.lval= 123
refcount= 1
type = IS_LONG
is_ref= 0
$b:
value.lval= 456
refcount= 1
type = IS_LONG
is_ref= 0
Full Reference
•is_ref为1.这个数值,refcount为引用的个数
•这时修改其中一个,其它的值也跟着修改
$a = 123;
$b = &$a;
这时有$a和$b都如下:
value.lval= 123
refcount= 2
type = IS_LONG
is_ref= 1
$b = 456;
这时的$a和$b如下:
value.lval= 456
refcount= 2
type = IS_LONG
is_ref= 1
操作zval 我们可以使用zend提供的一些宏把zval转换成正确的我们需要的数据类型,这些宏有:
文件zend_operator.h:
| #define Z_LVAL(zval) |
(zval).value.lval |
取得long值 |
| #define Z_BVAL(zval) |
((zend_bool)(zval).value.lval) |
取得boolean值:zend_bool |
| #define Z_DVAL(zval) |
(zval).value.dval |
取得double值 |
| #define Z_STRVAL(zval) |
(zval).value.str.val |
取得字符串值 |
| #define Z_STRLEN(zval) |
(zval).value.str.len |
取得字符串长度 |
| #define Z_ARRVAL(zval) |
(zval).value.ht |
取得数组,php数据在一种特殊的hashTable |
| #define Z_OBJVAL(zval) |
(zval).value.obj |
取得对象 |
| #define Z_OBJ_HANDLE(zval) |
Z_OBJVAL(zval).handle |
|
| #define Z_OBJ_HT(zval) |
Z_OBJVAL(zval).handlers |
|
| #define Z_OBJCE(zval) |
zend_get_class_entry(&(zval) TSRMLS_CC) |
|
| #define Z_OBJPROP(zval) |
Z_OBJ_HT((zval))->get_properties(&(zval) TSRMLS_CC) |
|
| #define Z_OBJ_HANDLER(zval, hf) |
Z_OBJ_HT((zval))->hf |
|
| #define Z_RESVAL(zval) |
(zval).value.lval |
|
| #define Z_LVAL_P(zval_p) |
Z_LVAL(*zval_p) |
|
| #define Z_BVAL_P(zval_p) |
Z_BVAL(*zval_p) |
|
| #define Z_DVAL_P(zval_p) |
Z_DVAL(*zval_p) |
|
| #define Z_STRVAL_P(zval_p) |
Z_STRVAL(*zval_p) |
|
| #define Z_STRLEN_P(zval_p) |
Z_STRLEN(*zval_p) |
|
| #define Z_ARRVAL_P(zval_p) |
Z_ARRVAL(*zval_p) |
|
| #define Z_OBJPROP_P(zval_p) |
Z_OBJPROP(*zval_p) |
|
| #define Z_OBJCE_P(zval_p) |
Z_OBJCE(*zval_p) |
|
| #define Z_RESVAL_P(zval_p) |
Z_RESVAL(*zval_p) |
|
| #define Z_OBJVAL_P(zval_p) |
Z_OBJVAL(*zval_p) |
|
| #define Z_OBJ_HANDLE_P(zval_p) |
Z_OBJ_HANDLE(*zval_p) |
|
| #define Z_OBJ_HT_P(zval_p) |
Z_OBJ_HT(*zval_p) |
|
| #define Z_OBJ_HANDLER_P(zval_p, h) |
Z_OBJ_HANDLER(*zval_p, h) |
|
| #define Z_LVAL_PP(zval_pp) |
Z_LVAL(**zval_pp) |
|
| #define Z_BVAL_PP(zval_pp) |
Z_BVAL(**zval_pp) |
|
| #define Z_DVAL_PP(zval_pp) |
Z_DVAL(**zval_pp) |
|
| #define Z_STRVAL_PP(zval_pp) |
Z_STRVAL(**zval_pp) |
|
| #define Z_STRLEN_PP(zval_pp) |
Z_STRLEN(**zval_pp) |
|
| #define Z_ARRVAL_PP(zval_pp) |
Z_ARRVAL(**zval_pp) |
|
| #define Z_OBJPROP_PP(zval_pp) |
Z_OBJPROP(**zval_pp) |
|
| #define Z_OBJCE_PP(zval_pp) |
Z_OBJCE(**zval_pp) |
|
| #define Z_RESVAL_PP(zval_pp) |
Z_RESVAL(**zval_pp) |
|
| #define Z_OBJVAL_PP(zval_pp) |
Z_OBJVAL(**zval_pp) |
|
| #define Z_OBJ_HANDLE_PP(zval_p) |
Z_OBJ_HANDLE(**zval_p) |
|
| #define Z_OBJ_HT_PP(zval_p) |
Z_OBJ_HT(**zval_p) |
|
| #define Z_OBJ_HANDLER_PP(zval_p, h) |
Z_OBJ_HANDLER(**zval_p, h) |
|
| #define Z_TYPE(zval) |
(zval).type |
|
| #define Z_TYPE_P(zval_p) |
Z_TYPE(*zval_p) |
|
| #define Z_TYPE_PP(zval_pp) |
Z_TYPE(**zval_pp) |