前言
下面我们大概了解下PHP7的变量类型都有哪些,是如何存储变量的。
zval结构定义
PHP7中是使用zval结构存储变量信息的。zval结构的定义在./Zend/zend_types.h文件中定义。
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类型的定义如下:
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的方法。
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");
}
}