php扩展开发-变量

我们在php中用到的变量,在底层的C语言代码里是一个结构体,由四个成员组成
typedef struct _zval_struct { zvalue_value value; /* 变量的值,也是一个结构体 */ zend_uint refcount__gc; /* 变量的引用计数 typedef unsigned int zend_uint */ zend_uchar type; /* 变量的类型 typedef unsigned char zend_uchar */ zend_uchar is_ref__gc; /* 是否引用 typedef unsigned char zend_uchar*/
} zval;
typedef union _zvalue_value {
    long lval;                 /* 长整型,存储整数,bool,资源类型 */
    double dval;               /* 浮点型,存储小数 */
    struct {                   
        char *val;
        int len;               /*  */
    } str;                     /* 字符串,val是字符串指针,len是字符串长度 */
    HashTable *ht;             /* hashtable 即PHP数组 */
    zend_object_value obj;     /* php对象 */
} zvalue_value;

php变量的类型,即zval的type成员,一共有8种

 
类型  zvalue_value中存储的成员说明
IS_NULL 不存储值 NULL
IS_LONG lval 整型
IS_DOUBLE dval 浮点型
IS_BOOL lval 布尔
IS_RESOURCE lval 资源
IS_STRING str 字符串
IS_ARRAY ht 数组
IS_OBJECT obj 对象

 

 

 

 

 

 

 

 

 

这些类型都是宏定义,在Zend/zend.h中可以查到

1 #define IS_NULL     0
2 #define IS_LONG     1
3 #define IS_DOUBLE   2
4 #define IS_BOOL     3
5 #define IS_ARRAY    4
6 #define IS_OBJECT   5
7 #define IS_STRING   6
8 #define IS_RESOURCE 7

通常我们不会直接使用php变量的成员,例如zval->type或zvalue_value->lval,为了代码的兼容性,zend给我们提供了很多的API方便我们操作变量

宏定义原型获取变量  描述
zend_uchar Z_TYPE(zval zv) type 返回变量类型
long Z_LVAL(zval zv) value.lval  返回zvalue_value的lval成员
zend_bool Z_BVAL(zval zv) value.lval  返回zvalue_value的lval成员,并且转换成zend_bool类型
double Z_DVAL(zval zv) value.dval  
long Z_RESVAL(zval zv) value.lval 返回zvalue_value的lval成员,此时的type是IS_RESOURCE
char* Z_STRVAL(zval zv) value.str.val 返回字符串的值
int Z_STRLEN(zval zv) value.str.len 返回字符串的长度
HashTable* Z_ARRVAL(zval zv) value.ht 返回hashtable即数组
zend_object_value Z_OBJVAL(zval zv) value.obj returns object value
uint Z_OBJ_HANDLE(zval zv) value.obj.handle returns the object handle for object value
zend_object_handlers* Z_OBJ_HT_P(zval zv) value.obj.handlers returns the handler table for object value
zend_class_entry* Z_OBJCE(zval zv) value.obj returns the class entry for object value
HashTable* Z_OBJPROP(zval zv) value.obj returns the properties of object value
HashTable* Z_OBJPROP(zval zv) value.obj returns the properties of object value
HashTable* Z_OBJDEBUG(zval zv) value.obj if an object has the get_debug_info handler set, it is called, else Z_OBJPROP is called

 

 

 

 

 

 

 

 

 

 

 

 

 

以上这些API其实就是宏定义,上面列出的每个宏同时都有另外两种类似的定义,以Z_TYPE为例

#define Z_TYPE(zval)        (zval).type         //参数是zval
#define Z_TYPE_P(zval_p)    Z_TYPE(*zval_p)     //参数是zval的指针
#define Z_TYPE_PP(zval_pp)  Z_TYPE(**zval_pp)   //参数是zval的指针的指针
以上这些宏定义,在Zend/zend_operators.h中可以查到
 1 #define Z_LVAL(zval)            (zval).value.lval
 2 #define Z_BVAL(zval)            ((zend_bool)(zval).value.lval)
 3 #define Z_DVAL(zval)            (zval).value.dval
 4 #define Z_STRVAL(zval)          (zval).value.str.val
 5 #define Z_STRLEN(zval)          (zval).value.str.len
 6 #define Z_ARRVAL(zval)          (zval).value.ht
 7 #define Z_AST(zval)         (zval).value.ast
 8 #define Z_OBJVAL(zval)          (zval).value.obj
 9 #define Z_OBJ_HANDLE(zval)      Z_OBJVAL(zval).handle
10 #define Z_OBJ_HT(zval)          Z_OBJVAL(zval).handlers
11 #define Z_OBJCE(zval)           zend_get_class_entry(&(zval) TSRMLS_CC)
12 #define Z_OBJPROP(zval)         Z_OBJ_HT((zval))->get_properties(&(zval) TSRMLS_CC)
13 #define Z_OBJ_HANDLER(zval, hf) Z_OBJ_HT((zval))->hf
14 #define Z_RESVAL(zval)          (zval).value.lval
15 #define Z_OBJDEBUG(zval,is_tmp) (Z_OBJ_HANDLER((zval),get_debug_info)?Z_OBJ_HANDLER((zval),get_debug_info)(&(zval),&is_tmp TSRMLS_CC):(is_tmp=0,Z_OBJ_HANDLER((zval),get_properties)?Z_OBJPROP(zval):NULL))
16 
17 #define Z_LVAL_P(zval_p)        Z_LVAL(*zval_p)
18 #define Z_BVAL_P(zval_p)        Z_BVAL(*zval_p)
19 #define Z_DVAL_P(zval_p)        Z_DVAL(*zval_p)
20 #define Z_STRVAL_P(zval_p)      Z_STRVAL(*zval_p)
21 #define Z_STRLEN_P(zval_p)      Z_STRLEN(*zval_p)
22 #define Z_ARRVAL_P(zval_p)      Z_ARRVAL(*zval_p)
23 #define Z_AST_P(zval_p)         Z_AST(*zval_p)
24 #define Z_OBJPROP_P(zval_p)     Z_OBJPROP(*zval_p)
25 #define Z_OBJCE_P(zval_p)       Z_OBJCE(*zval_p)
26 #define Z_RESVAL_P(zval_p)      Z_RESVAL(*zval_p)
27 #define Z_OBJVAL_P(zval_p)      Z_OBJVAL(*zval_p)
28 #define Z_OBJ_HANDLE_P(zval_p)  Z_OBJ_HANDLE(*zval_p)
29 #define Z_OBJ_HT_P(zval_p)      Z_OBJ_HT(*zval_p)
30 #define Z_OBJ_HANDLER_P(zval_p, h)  Z_OBJ_HANDLER(*zval_p, h)
31 #define Z_OBJDEBUG_P(zval_p,is_tmp) Z_OBJDEBUG(*zval_p,is_tmp)
32 
33 #define Z_LVAL_PP(zval_pp)      Z_LVAL(**zval_pp)
34 #define Z_BVAL_PP(zval_pp)      Z_BVAL(**zval_pp)
35 #define Z_DVAL_PP(zval_pp)      Z_DVAL(**zval_pp)
36 #define Z_STRVAL_PP(zval_pp)    Z_STRVAL(**zval_pp)
37 #define Z_STRLEN_PP(zval_pp)    Z_STRLEN(**zval_pp)
38 #define Z_ARRVAL_PP(zval_pp)    Z_ARRVAL(**zval_pp)
39 #define Z_AST_PP(zval_p)        Z_AST(**zval_p)
40 #define Z_OBJPROP_PP(zval_pp)   Z_OBJPROP(**zval_pp)
41 #define Z_OBJCE_PP(zval_pp)     Z_OBJCE(**zval_pp)
42 #define Z_RESVAL_PP(zval_pp)    Z_RESVAL(**zval_pp)
43 #define Z_OBJVAL_PP(zval_pp)    Z_OBJVAL(**zval_pp)
44 #define Z_OBJ_HANDLE_PP(zval_p) Z_OBJ_HANDLE(**zval_p)
45 #define Z_OBJ_HT_PP(zval_p)     Z_OBJ_HT(**zval_p)
46 #define Z_OBJ_HANDLER_PP(zval_p, h)     Z_OBJ_HANDLER(**zval_p, h)
47 #define Z_OBJDEBUG_PP(zval_pp,is_tmp)   Z_OBJDEBUG(**zval_pp,is_tmp)

如果你是初始变量赋值,或者需要同时改变变量的类型,你可以直接使用以下这些宏定义函数

#define ZVAL_RESOURCE(z, l) do {    \//资源类型,值为l
        zval *__z = (z);            \
        Z_LVAL_P(__z) = l;          \
        Z_TYPE_P(__z) = IS_RESOURCE;\
    } while (0)

#define ZVAL_BOOL(z, b) do {        \//布尔类型
        zval *__z = (z);            \
        Z_LVAL_P(__z) = ((b) != 0); \
        Z_TYPE_P(__z) = IS_BOOL;    \
    } while (0)

#define ZVAL_NULL(z) {              \//NULL
        Z_TYPE_P(z) = IS_NULL;      \
    }

#define ZVAL_LONG(z, l) {           \//整型
        zval *__z = (z);            \
        Z_LVAL_P(__z) = l;          \
        Z_TYPE_P(__z) = IS_LONG;    \
    }

#define ZVAL_DOUBLE(z, d) {         \//浮点型
        zval *__z = (z);            \
        Z_DVAL_P(__z) = d;          \
        Z_TYPE_P(__z) = IS_DOUBLE;  \
    }

#define ZVAL_STRING(z, s, duplicate) do {   \//字符串,duplicate表示是否赋值一份字符串再赋值
        const char *__s=(s);                \
        zval *__z = (z);                    \
        Z_STRLEN_P(__z) = strlen(__s);      \
        if (UNEXPECTED(Z_STRLEN_P(__z) < 0)) { \
            zend_error(E_ERROR, "String size overflow"); \
        }                                   \
        Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\
        Z_TYPE_P(__z) = IS_STRING;          \
    } while (0)

#define ZVAL_STRINGL(z, s, l, duplicate) do {   \//字符串,l表示字符串的长度
        const char *__s=(s); int __l=l;         \
        zval *__z = (z);                        \
        Z_STRLEN_P(__z) = __l;                  \
        Z_STRVAL_P(__z) = (duplicate?estrndup(__s, __l):(char*)__s);\
        Z_TYPE_P(__z) = IS_STRING;              \
    } while (0)

#define ZVAL_EMPTY_STRING(z) do {   \//设置空字符串
        zval *__z = (z);            \
        Z_STRLEN_P(__z) = 0;        \
        Z_STRVAL_P(__z) = STR_EMPTY_ALLOC();\
        Z_TYPE_P(__z) = IS_STRING;  \
    } while (0)

#define ZVAL_ZVAL(z, zv, copy, dtor) do {       \//赋值一个zval变量,copy表示是否硬拷贝zval中的数据,dtor表示是否对zv尝试unset
        zval *__z = (z);                        \
        zval *__zv = (zv);                      \
        ZVAL_COPY_VALUE(__z, __zv);             \
        if (copy) {                             \
            zval_copy_ctor(__z);                \
        }                                       \
        if (dtor) {                             \
            if (!copy) {                        \
                ZVAL_NULL(__zv);                \
            }                                   \
            zval_ptr_dtor(&__zv);               \
        }                                       \
    } while (0)

#define ZVAL_FALSE(z)                   ZVAL_BOOL(z, 0)//布尔值TRUE
#define ZVAL_TRUE(z)                    ZVAL_BOOL(z, 1)//布尔值FALSE

接着我们来看一下变量的创建,复制和销毁的相关内容和操作的API

宏定义说明
ALLOC_ZVAL(zval* pzval) 为变量分配空间
ALLOC_INIT_ZVAL(zval* pzval) 为变量分配空间,并且初始化变量为NULL类型
MAKE_STD_ZVAL(zval* pzval) 为变量分配空间,并且设置refcount__gc = 1,is_ref__gc = 0
ZVAL_COPY_VALUE(zval* dst, zval* src) 复制变量,dst的value和type分别等于src的value和type
INIT_PZVAL_COPY(zval* dst, zval*dst) 先执行ZVAL_COPY_VALUE,然后设置dst的refcount__gc = 1,is_ref__gc = 0
SEPARATE_ZVAL(zval** ppzval) 如果*ppzval的refcount__gc > 1, 则创建一个新的变量*zvalnew,用INIT_PZVAL_COPY函数来复制原变量,最后把ppzval指向新的变量
SEPARATE_ZVAL_IF_NOT_REF(zval** ppzval) 如果*ppzval不是一个引用(is_ref_gc = 0), 则执行SEPARATE_ZVAL(zval** ppzval)
SEPARATE_ZVAL_TO_MAKE_IS_REF(zval** ppzval) 如果*ppzval不是一个引用(is_ref_gc = 0), 则执行SEPARATE_ZVAL(zval** ppzval)接着执行Z_SET_ISREF_PP(zval** ppzval)设置is_ref__gc = 0
COPY_PZVAL_TO_ZVAL(zval dst, zval** src) results in dst being a copy of src without affecting the refcount of src
MAKE_COPY_ZVAL(zval** src, zval* dst) performs INIT_PZVAL_COPY, then zval_copy_ctor on the new zval
void zval_copy_ctor(zval* pzval) 把pzval的数据复制一份出来。
void zval_ptr_dtor(zval* pzval) 把pzval->refcount__gc减1,如果refcount__gc此时等于0,则销毁pzval指向的变量回收空间。
FREE_ZVAL(zval* pzval) free(pzval)回收空间

 

 

 

 

 

 

 

 

 

 

 

//zend.h
#define INIT_PZVAL(z)       \
    (z)->refcount__gc = 1;  \
    (z)->is_ref__gc = 0;

#define INIT_ZVAL(z) z = zval_used_for_init;

#define ALLOC_INIT_ZVAL(zp)                     \
    ALLOC_ZVAL(zp);     \
    INIT_ZVAL(*zp);

#define MAKE_STD_ZVAL(zv)                \
    ALLOC_ZVAL(zv); \
    INIT_PZVAL(zv);

#define PZVAL_IS_REF(z)     Z_ISREF_P(z)

#define ZVAL_COPY_VALUE(z, v)                   \
    do {                                        \
        (z)->value = (v)->value;                \
        Z_TYPE_P(z) = Z_TYPE_P(v);              \
    } while (0)

#define INIT_PZVAL_COPY(z, v)                   \
    do {                                        \
        ZVAL_COPY_VALUE(z, v);                  \
        Z_SET_REFCOUNT_P(z, 1);                 \
        Z_UNSET_ISREF_P(z);                     \
    } while (0)

#define SEPARATE_ZVAL(ppzv)                     \
    do {                                        \
        if (Z_REFCOUNT_PP((ppzv)) > 1) {        \
            zval *new_zv;                       \
            Z_DELREF_PP(ppzv);                  \
            ALLOC_ZVAL(new_zv);                 \
            INIT_PZVAL_COPY(new_zv, *(ppzv));   \
            *(ppzv) = new_zv;                   \
            zval_copy_ctor(new_zv);             \
        }                                       \
    } while (0)

#define SEPARATE_ZVAL_IF_NOT_REF(ppzv)      \
    if (!PZVAL_IS_REF(*ppzv)) {             \
        SEPARATE_ZVAL(ppzv);                \
    }

#define SEPARATE_ZVAL_TO_MAKE_IS_REF(ppzv)  \
    if (!PZVAL_IS_REF(*ppzv)) {             \
        SEPARATE_ZVAL(ppzv);                \
        Z_SET_ISREF_PP((ppzv));             \
    }

#define COPY_PZVAL_TO_ZVAL(zv, pzv)         \
    (zv) = *(pzv);                          \
    if (Z_REFCOUNT_P(pzv)>1) {              \
        zval_copy_ctor(&(zv));              \
        Z_DELREF_P((pzv));                  \
    } else {                                \
        FREE_ZVAL(pzv);                     \
    }                                       \
    INIT_PZVAL(&(zv));

#define MAKE_COPY_ZVAL(ppzv, pzv)   \
    INIT_PZVAL_COPY(pzv, *(ppzv));  \
    zval_copy_ctor((pzv));

#define REPLACE_ZVAL_VALUE(ppzv_dest, pzv_src, copy) {  \
    int is_ref, refcount;                       \
                                                \
    SEPARATE_ZVAL_IF_NOT_REF(ppzv_dest);        \
    is_ref = Z_ISREF_PP(ppzv_dest);             \
    refcount = Z_REFCOUNT_PP(ppzv_dest);        \
    zval_dtor(*ppzv_dest);                      \
    ZVAL_COPY_VALUE(*ppzv_dest, pzv_src);       \
    if (copy) {                                 \
        zval_copy_ctor(*ppzv_dest);             \
    }                                           \
    Z_SET_ISREF_TO_PP(ppzv_dest, is_ref);       \
    Z_SET_REFCOUNT_PP(ppzv_dest, refcount);     \
}

#define SEPARATE_ARG_IF_REF(varptr) \
    if (PZVAL_IS_REF(varptr)) { \
        zval *original_var = varptr; \
        ALLOC_ZVAL(varptr); \
        INIT_PZVAL_COPY(varptr, original_var); \
        zval_copy_ctor(varptr); \
    } else { \
        Z_ADDREF_P(varptr); \
    }

 除了获取类型和值之外,还有一些操作跟l变量的refcount__gc和is_ref__gc相关 

宏定义原型  描述
zend_uint Z_REFCOUNT(zval zv) 返回refcount__gc的值
zend_uint Z_SET_REFCOUNT(zval zv) 设置zval变量的refcount__gc并返回
zend_uint Z_ADDREF(zval zv) ++zval->refcount__gc并返回
zend_uint Z_DELREF(zval zv) --zval->refcount__gc并返回
zend_bool Z_ISREF(zval zv) 返回zval->is_ref__gc
void Z_UNSET_ISREF(zval zv) set is_ref__gc to 0
void Z_SET_ISREF(zval zv) set is_ref__gc to 1
void Z_SET_ISREF_TO(zval zv, zend_uchar to) set is_ref__gc to to

 

 

 

 

 

 

 

这些宏定义也同样有*_P或*_PP的版本,可以在Zend/zend.h中查看

 1 #define Z_REFCOUNT_PP(ppz)      Z_REFCOUNT_P(*(ppz))
 2 #define Z_SET_REFCOUNT_PP(ppz, rc)  Z_SET_REFCOUNT_P(*(ppz), rc)
 3 #define Z_ADDREF_PP(ppz)        Z_ADDREF_P(*(ppz))
 4 #define Z_DELREF_PP(ppz)        Z_DELREF_P(*(ppz))
 5 #define Z_ISREF_PP(ppz)         Z_ISREF_P(*(ppz))
 6 #define Z_SET_ISREF_PP(ppz)     Z_SET_ISREF_P(*(ppz))
 7 #define Z_UNSET_ISREF_PP(ppz)       Z_UNSET_ISREF_P(*(ppz))
 8 #define Z_SET_ISREF_TO_PP(ppz, isref)   Z_SET_ISREF_TO_P(*(ppz), isref)
 9 
10 #define Z_REFCOUNT_P(pz)        zval_refcount_p(pz)
11 #define Z_SET_REFCOUNT_P(pz, rc)    zval_set_refcount_p(pz, rc)
12 #define Z_ADDREF_P(pz)          zval_addref_p(pz)
13 #define Z_DELREF_P(pz)          zval_delref_p(pz)
14 #define Z_ISREF_P(pz)           zval_isref_p(pz)
15 #define Z_SET_ISREF_P(pz)       zval_set_isref_p(pz)
16 #define Z_UNSET_ISREF_P(pz)     zval_unset_isref_p(pz)
17 #define Z_SET_ISREF_TO_P(pz, isref) zval_set_isref_to_p(pz, isref)
18 
19 #define Z_REFCOUNT(z)           Z_REFCOUNT_P(&(z))
20 #define Z_SET_REFCOUNT(z, rc)       Z_SET_REFCOUNT_P(&(z), rc)
21 #define Z_ADDREF(z)         Z_ADDREF_P(&(z))
22 #define Z_DELREF(z)         Z_DELREF_P(&(z))
23 #define Z_ISREF(z)          Z_ISREF_P(&(z))
24 #define Z_SET_ISREF(z)          Z_SET_ISREF_P(&(z))
25 #define Z_UNSET_ISREF(z)        Z_UNSET_ISREF_P(&(z))
26 #define Z_SET_ISREF_TO(z, isref)    Z_SET_ISREF_TO_P(&(z), isref)

 我们会在扩展的开发过程中,频繁用到这些zend提供的API操作,你不需要把它记下来,随着开发的进行,你将会慢慢习惯这些API的使用。我们在开发的过程中,经常还需要转换变量的类型,可以使用下面这些函数。

//把zval *pzval的变量转换其它类型
void
convert_to_long(zval* pzval)//整型 void convert_to_double(zval* pzval)//浮点 void convert_to_long_base(zval* pzval, int base)//整型,base表示进制,2,8,10,16等 void convert_to_null(zval* pzval)//NULL void convert_to_boolean(zval* pzval)//布尔 void convert_to_array(zval* pzval)//数组 void convert_to_object(zval* pzval)//对象 void convert_object_to_type(zval* pzval, convert_func_t converter)//根据回调函数转换成对象 convert_func_t functions should have the prototype (void) (zval* pzval)//接上,回调函数的原型

posted on 2016-12-04 15:57  平淡生活781  阅读(799)  评论(0编辑  收藏  举报

导航