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*指针,建辉在下一章讲解.
Extending.and.Embedding.PHP读书笔记(4)-php变量
最新推荐文章于 2024-09-04 14:43:35 发布