PHP作为一门弱类型语言,其变量类型可任意改变。而C作为PHP的底层实现,是通过结构及联合来实现PHP变量的弱类型特性的。在PHP源码中,Zend/zend.h文件有关于PHP变量的结构定义。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
typedef struct _zval_struct zval;
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value; struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
}; |
PHP的变量值,存储于zvalue_value这个联合当中。从其定义可以看出PHP是如何实现单一变量支持不同类型的。lval实现整型及资源类型的存储,dval实现长整型或浮点型存储,str实现字符串的存储,ht是一个哈希表的指针,用于数组的实现,obj实现对象类型。
再看看zval这个结构,zval是实现PHP变量存储机制的核心。包含四个成员,value是变量值,type表示变量的类型,为unsigned char类型,其值在内核中有对应的常量定义,分别对应PHP的八种数据类型。这八个常量是:IS_NULL, IS_BOOL, IS_LONG, IS_DOUBLE, IS_STRING, IS_ARRAY, IS_OBJECT, IS_RESOURCE。可见,根据type和value两个成员,即可实现PHP当中的八种变量类型。假如有以下PHP代码:
1
2
3
4
|
$a = 4323;
echo $a ;
$a = "hello world" ;
echo $a ;
|
运行第一句的时候,变量$a对应的zval结构当中的type成员值设置为IS_LONG,取值打印的时候就取value中的lval成员。然后运行第三句,将一个字符串赋值给变量$a,此时对应的zval结构的type成员值就被设置成了IS_STRING,然后取值的时候就根据value中的str结构的字符指针去获取字符串。