hp变量在底层中是通过一个zval的结构体来实现。zval这个结构体的定义:
struct _zval_struct {
zvalue_value value; /* 变量的值 */
zend_uint refcount__gc;
zend_uchar type; /* 变量当前的数据类型 */
zend_uchar is_ref__gc;
};
typedef struct _zval_struct zval;
在Zend/zend.h里面可以找到答案。
//在Zend/zend_types.h里定义的:
typedef unsigned int zend_uint;
typedef unsigned char zend_uchar;
zval里的refcout__gc是zend_uint类型,也就是unsigned int型,is_ref__gc和type则是unsigned char型的。
保存变量值的value则是zvalue_value类型(PHP5),它是一个Union,同样定义在了Zend/zend.h文件里:
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;
在以上实现的基础上,PHP语言得以实现了8种数据类型,这些数据类型在内核中的分别对应于特定的常量,它们分别是:IS_NULL,IS_BOOL,IS_LONG,IS_DOUBLE,IS_STRING,IS_OBJECT,IS_ARRAY,IS_SOURCE。
在内核中如果需要检测变量的类型用:Z_TYPE_P 和Z_TYPE_PP. 前者的参数是zval型,而后者的参数则是**zval(指针的指针)。
PHP内核提供了三个基础宏来方便我们对变量的值进行操作,这几个宏同样以Z_开头,并且P结尾和PP结尾的同上一节中的宏一样,分别代表这参数是指针还是指针的指针。
内核在保存String型变量时,不仅保存了字符串的值,还保存了它的长度,所以它有对应的两种宏组合STRVAL和STRLEN,即:Z_STRVAL、Z_STRVAL_P、Z_STRVAL_PP与Z_STRLEN、Z_STRLEN_P、Z_STRLEN_PP。前一种宏返回的是char *型,即字符串的地址;后一种返回的是int型,即字符串的长度。
MAKE_STD_ZVAL(pzv)。这个宏会用内核的方式来申请一块内存并将其地址付给pzv,并初始化它的refcount和is_ref连个属性. 除了MAKE_STD_ZVAL()宏函数,ALLOC_INIT_ZVAL()宏函数也是用来干这件事的,唯一的不同便是它会将pzv所指的zval的类型设置为IS_NULL
当PHP中定义了一个变量,内核会自动的把它的信息储存到一个用HashTable实现的符号表里。
symbol_table元素可以通过EG宏来访问,它代表着PHP的全局变量。
EG(active_symbol_table)代表当前作用域的变量符合表。
通过zend_hash_find()函数来找到当前某个作用域下用户已经定义好的变量。
change_zval_to_string将任意类型的zval转换成字符串。
convert_to_long(zval *op);
convert_to_double(zval *op);
void convert_to_null(zval *op);
void convert_to_boolean(zval *op);
void convert_to_array(zval *op);
void convert_to_object(zval *op);