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種php

 
類型   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中能夠查到api

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)

若是你是初始變量賦值,或者須要同時改變變量的類型,你能夠直接使用如下這些宏定義函數ui

#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

接着咱們來看一下變量的建立,複製和銷燬的相關內容和操做的APIspa

宏定義 說明
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相關 prototype

宏定義原型   描述
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中查看debug

 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)//接上,回調函數的原型
相關文章
相關標籤/搜索