查看文章
 
Zend Engine学习之数据结构类型
2008-12-23 11:17
在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)

类别:Zend||添加到搜藏 |分享到i贴吧|浏览(169)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu