zoukankan      html  css  js  c++  java
  • 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)//接上,回调函数的原型
  • 相关阅读:
    actionBar-进入界面闪烁问题解决
    softInputMode- 软件盘的设置
    LinearLayout -设置负值属性
    launcher- 第三方应用图标替换
    resource-color 的引用
    java学习笔记——IO流部分
    二进制基础
    java学习笔记——IO部分(遍历文件夹)
    Java线程:线程的同步与锁
    AWT与Swing的区别
  • 原文地址:https://www.cnblogs.com/wuhen781/p/6130990.html
Copyright © 2011-2022 走看看