ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 前言 下面我们大概了解下PHP7的变量类型都有哪些,是如何存储变量的。 ## zval结构定义 PHP7中是使用zval结构存储变量信息的。zval结构的定义在[./Zend/zend_types.h](https://github.com/php/php-src/blob/master/Zend/zend_types.h)文件中定义。 ```c struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* call info for EX(This) */ } v; uint32_t type_info; } u1; union { uint32_t var_flags; uint32_t next; /* hash collision chain */ uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ } u2; }; ``` ## 变量的值 通过上面的代码我们可以看到。变量是通过一个`_zval_struct`结构体方式存储的。其中结构体中的value存储的是变量的值。这个成员是`zend_value`类型的。`zend_value`类型的定义如下: ```c typedef union _zend_value { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww; } zend_value; ``` zend_value是一个联合体。对于小于64位的简单类型,会直接存储值。如,long double。而对于其他比较复杂的类型,如字符串,数组,对象等,是存储的指针。这样,对于简单类型来说,变得简单高效。 ## 获取变量类型 zval联合体的type存储的是变量的类型。PHP7已经提供了我们获取变量类型的宏方法Z_TYPE。宏方法的定义如下: ``` static zend_always_inline zend_uchar zval_get_type(const zval* pz) { return pz->u1.v.type; } #define Z_TYPE(zval) zval_get_type(&(zval)) #define Z_TYPE_P(zval_p) Z_TYPE(*(zval_p)) ``` ## 设置变量类型 在PHP7中,设置变量类型提供了新的方法。 ``` #define Z_TYPE_INFO(zval) (zval).u1.type_info #define Z_TYPE_INFO_P(zval_p) Z_TYPE_INFO(*(zval_p)) ``` ## 代码实例 下面的代码实现了一个类似`var_dump`的方法。 ```c PHP_FUNCTION(dump) { zval *arg; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) { return; } switch (Z_TYPE_P(arg)) { case IS_NULL: RETVAL_STRING("NULL"); break; case IS_TRUE: RETVAL_STRING("true"); break; case IS_FALSE: RETVAL_STRING("false"); break; case IS_LONG: RETVAL_STRING("integer"); break; case IS_DOUBLE: RETVAL_STRING("double"); break; case IS_STRING: RETVAL_STRING("string"); break; case IS_ARRAY: RETVAL_STRING("array"); break; case IS_OBJECT: RETVAL_STRING("object"); break; case IS_RESOURCE: RETVAL_STRING("resource"); break; default: RETVAL_STRING("unknown type"); } } ```