## 前言
下面我們大概了解下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");
}
}
```