在前面的文章多次提到了zval结构,其实所有用户定义的变量在PHP中都是用zval类型来表示的,当我门 使用zend_parse_parameters函数解析参数时,Zend引擎会根据相应的数据类型进行类型转换,而由于PHP中的数组、对象和资源类 型,在C语言中没有对应的类型,所以无法进行类型转换,它们都使用zval表示,先看一下zval结构定义:
typedef pval zval; typedef struct _zval_struct zval; struct _zval_struct { zvalue_value value; unsigned char type; unsigned char is_ref; short refcount; };
zval结构的定义使用了C语言中的联合类型,各个字段说明如下:
value
type
is_ref
refcount
变量类型定义:
IS_NULL
IS_LONG
IS_DOUBLE
IS_STRING
IS_ARRAY
IS_OBJECT
IS_BOOL
IS_RESOURCE
IS_STRING
zvalue_value结构定义:
typedef union _zvalue_value { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; struct { zend_class_entry *ce; HashTable *properties; } obj; } zvalue_value;
zvalue_value结构的说明如下:
lval
dval
str
ht
obj
给定一个具体的zval,可用三个便利的宏中的一个测试它的类型:Z_TYPE(zval)、Z_TYPE_P(zval*)或Z_TYPE_PP(zval**)。三者之间仅有的功能上的区别在于传入的变量所期望的间接的级别。如下面的示例:
PHP_FUNCTION(hello_dump) { zval *uservar; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &uservar) == FAILURE) { RETURN_NULL(); } switch (Z_TYPE_P(uservar)) { case IS_NULL: php_printf("NULL\n"); break; case IS_BOOL: php_printf("Boolean: %s\n", Z_LVAL_P(uservar) ? "TRUE" : "FALSE"); break; case IS_LONG: php_printf("Long: %ld\n", Z_LVAL_P(uservar)); break; case IS_DOUBLE: php_printf("Double: %f\n", Z_DVAL_P(uservar)); break; case IS_STRING: php_printf("String: "); PHPWRITE(Z_STRVAL_P(uservar), Z_STRLEN_P(uservar)); php_printf("\n"); break; case IS_RESOURCE: php_printf("Resource\n"); break; case IS_ARRAY: php_printf("Array\n"); break; case IS_OBJECT: php_printf("Object\n"); break; default: php_printf("Unknown\n"); } RETURN_TRUE; }
编写一个简单的测试脚本:
运行后效果如下:
在PHP扩展中对于用户传过来的参数,本质上都是一个zval结构,我们需要调用一些转换函数进行强制类型转换(zend_parse_parameters函数会对基本类型做转换),Zend引擎提供了convert_to_xxx系列函数帮助我们进行类型转换:
convert_to_boolean_ex()
convert_to_long_ex()
convert_to_double_ex()
convert_to_string_ex()
convert_to_array_ex(value)
convert_to_object_ex(value)
convert_to_null_ex(value)
关于zval结构的介绍就到这里了。
未经允许不得转载:天宝寺||陈瑞轩 » PHP扩展开发(7):zval结构