Extending.and.Embedding.PHP读书笔记(4)-php变量

 1.php是松散变量类型的语言,即变量可以不经过声明便可以使用,变量可以存储任何类型的值

2.比较重要的数据类型
在Zend/zend.h中定义的zval zvalue_value
typedef struct _zval_struct {
    zvalue_value value;
    zend_uint refcount;
    zend_uchar type;
    zend_uchar is_ref;
} zval;
typedef union _zvalue_value {
    long lval;
    double dval;
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;
    zend_object_value obj;
} zvalue_value;

zval.type可以取的值
IS_NULL IS_BOOL IS_LONG IS_DOUBLE IS_STRING  IS_ARRAY IS_OBJECT IS_RESOURCE
Z_TYPE()表示其参数直接为一个zval类型变量zval foo Z_TYPE_P()表示其参数为指向zval指针的变量zval *fooZ_TYPE_PP()其参数为zval **foo形式的

void describe_zval(zval *foo)
{
    if (Z_TYPE_P(foo) == IS_NULL) {
        php_printf("The variable is NULL");
    } else {
        php_printf("The variable is of type %d",
                            Z_TYPE_P(foo));
    }
}


3.数据值
php用专门的宏定义去获取每种类型变量的值,并且后面加P或者PP或者不加,来区别其变量的间接程度
Boolean-BVAL, long-LVAL,  double-DVAL

void display_values(zval boolzv, zval *longpzv,
                zval **doubleppzv)
{
    if (Z_TYPE(boolzv) == IS_BOOL) {
        php_printf("The value of the boolean is: %s/n",
            Z_BVAL(boolzv) ? "true" : "false");
    }
    if (Z_TYPE_P(longpzv) == IS_LONG) {
        php_printf("The value of the long is: %ld/n",
            Z_LVAL_P(longpzv));
    }
    if (Z_TYPE_PP(doubleppzv) == IS_DOUBLE) {
        php_printf("The value of the double is: %f/n",
            Z_DVAL_PP(doubleppzv));
    }
}

由于字符串类型的有两个变量,因此有一对宏定义来获取其值
void display_string(zval *zstr)
{
    if (Z_TYPE_P(zstr) != IS_STRING) {
        php_printf("The wrong datatype was passed!/n");
        return;
    }
    PHPWRITE(Z_STRVAL_P(zstr), Z_STRLEN_P(zstr));
}

数组类型是作为HashTable *类型来存储的,访问其值的宏定义有Z_ARRVAL(zv), Z_ARRVAL_P(pzv), Z_ARRVAL_PP(ppzv)

对象作为更复杂的内部结构,有着更多的宏定义来存取OBJ_HANDLE返回一个对象标示,OBJ_HT为handler表,OBJCE为类的定义,OBJPROP为属性的HashTable,OBJ_HANDLER为操作一个特定handler的一个方法,该方法在OBJ_HT表中

一个资源数据类型在zval作为一个简单的整型存储着,能够被RESVAL存取,该整数被传到zend_fetch_resource()中来寻找被注册的资源

3.数据创建
MAKE_STD_ZVAL(pzv)该宏在一个最佳化的内存区域为新变量分配一块内存空间,并自动处理分配错误,自动初始化新变量的refcount和is_ref属性.ALLOC_INIT_ZVAL()该宏与MAKE_STD_ZVAL的唯一区别在于其将新变量的类型置为IS_NULL.
现在要给新变量赋值了
Zend用了另外一组宏定义来设定zval*的值
ZVAL_NULL(pvz)    Z_TYPE_P(pvz) = IS_NULL
当然使用直接赋值的版本是不提供任何存储功能的
ZVAL_BOOL(pzv,b);    Z_TYPE_P(pzv) = IS_BOOL;
            Z_BVAL_P(pzv) = b ? 1: 0;
ZVAL_TRUE(pzv);                   ZVAL_BOOL(pzv, 1);
ZVAL_FALSE(pzv);                  ZVAL_BOOL(pzv, 0);
任何非0的值都回返回一个真值在ZVAL_BOOL中

ZVAL_LONG(pzv, l);                Z_TYPE_P(pzv) = IS_LONG;
                                  Z_LVAL_P(pzv) = l;
ZVAL_DOUBLE(pzv, d);              Z_TYPE_P(pzv) = IS_DOUBLE;
                                  Z_DVAL_P(pzv) = d;

字符串类型的
ZVAL_STRINGL(pzv,str,len,dup);    Z_TYPE_P(pzv) = IS_STRING;
                                  Z_STRLEN_P(pzv) = len;
                                  if (dup) {
                                      Z_STRVAL_P(pzv) =
                                            estrndup(str, len + 1);
                                  } else {
                                     Z_STRVAL_P(pzv) = str;
                                  }
ZVAL_STRING(pzv, str, dup);       ZVAL _STRINGL(pzv, str,
                                                strlen(str), dup);

ZVAL_RESOURCE(pzv, res);          Z_TYPE_P(pzv) = IS_RESOURCE;
                                  Z_RESVAL_P(pzv) = res;


4.数据存储
在php中,每个单独的变量都能在一个内部数组-symbol table中被找到.唯一一个全局的symbol table在扩展的RINIT函数被调用前初始化,并在RSHUTDOWN被执行后销毁

当一个对象的方法或者函数被调用时,便会为此方法或者函数分配一个新的symbol table,该symbol table被激活为avtive symbol table,如果当前没有执行函数或者方法,那么默认的全局symbol table便被认为是active symbol table

Zend/zend_globals.h
struct _zend_execution_globals {
    ...
    HashTable symbol_table;
    HashTable *active_symbol_table;
    ...
};
象EG(symbol_table)这样访问的那个symbol table永远是全局的那个,就好像是用户空间中的$GLOBALS变量
active_symbol_table同样可以这样访问EG(active_symbol_table),但是访问的仅仅是活动的那个symbol_table

看下面的代码
<?php $foo = 'bar'; ?>


In C:

{
    zval *fooval;

    MAKE_STD_ZVAL(fooval);
    ZVAL_STRING(fooval, "bar", 1);
    ZEND_SET_SYMBOL(EG(active_symbol_table), "foo", fooval);
}
首先使用MAKE_STD_ZVAL为一个新的变量fooval分配内存,它值被初始化为bar。然后一个新的宏,相等于等号,向活动symbol table中添加了一个值为fooval的变量$foo。此时,EG(active_symbol_table) == &EG(symbol_table)。变量被存储到了全局区域

5.变量的检索
下面的片断展示了从用户空间中用zend_hash_find函数寻找某个变量
{
    zval **fooval;

    if (zend_hash_find(EG(active_symbol_table),
                       "foo", sizeof("foo"),
                       (void**)&fooval) == SUCCESS) {
        php_printf("Got the value of $foo!");
    } else {
        php_printf("$foo is not defined.");
    }
}
上面的代码 fooval定义为两级间接,sizeof用于取得foo的长度 &fooval计算结果为 zval***,然后转变为void**,这是为什么呢?哈哈,我先自我得意一下,待会儿再说.

HashTables并不仅仅用作用户空间的变量,在整个引擎中,它是非常通用的结构,某些情况下是存储费指针值的完美方法.一个 HashTable bucket是固定大小的,为了存储任何大小的数据,一个HashTable必须分配一块内存用来包裹要存储的数据.在变量存储这这种情况中,zval*即一个指针值被存储,所以HashTable存储机制申请一块可以容下一个指针大小的内存.HashTable的bucket利用新的指针去携带zval*最后你用zval**使用在HashTable中的值.为什么在HashTable可以存储整个zval值时,仅仅存储一个zval*指针,建辉在下一章讲解.

发布了17 篇原创文章 · 获赞 1 · 访问量 5万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览