PHP中的變量可以保存任何的數據類型,這是因為它是弱類型語言。但php是用C語言編寫的,C語言是強類型語言,每個變量都有固定的類型,不能隨意改變變量的類型(可以通過強制類型轉變,不過有可能出現問題),在zend引擎中是怎樣可以做到一個變量保存任何類型的呢?
在zend/zend.h頭文件中,會發現下面的結構體:
typedef struct _zval_struct zval;
typedef union _zvalue_value {
long lval;
double dval;
struct {
char *val;
int len;
}str;
HashTable *ht;
zend_object_value obj;
} zvalue_value ;
struct _zval_struct {
zvalue_value value;
zend_uint refcount;
zend_uchar type;
zend_uchar is_ref;
};
zval結構體就是通常用到的PHP變量在內核中的表達方式。在zval結構體中,可以看到4個成員變量,分別是:
zvalue_value value; //變量的值,PHP變量的值就保存在這裡
zend_uint refcount; //變量引用數,變量引用計算器
zend_uchar type; //變量的類型
zend_uchar is_ref; //變量是否被引用
zval結構體的value成員變量是一個zvalue_value聯合體,PHP能夠保持任何的結構類型就是因為這個聯合體 。從zvalue_value聯合體的成員變量中可以看到,不同類型會保存到不同的成員變量中,這樣就實現了PHP變量可以存儲任何數據類型。例如,當變量是整數類型時,會保存到value的lval成員變量中;當變量的類型是字符串時,又會保存到value的str成員變量中。
還有一個問題,就是zend引擎是怎麼知道這個變量保存的是什麼類型呢?我們注意到,zval結構體中有個type成員變量,這個成員變量就是要保存一個php變量的類型。
zend引擎定義了8中變量類型:
#define IS_NULL 0
#define IS_LONG 1
#define IS_DOUBLE 2
#define IS_STRING 3
#define IS_ARRAY 4
#define IS_OBJECT 5
#define IS_BOOL 6
#define IS_RESOURCE 7
每一個宏定義對應php語言層的一種類型,例如當zval的type成員變量等於IS_STRING時(zval.type==IS_STRING
),說明這個變量的類型是字符串類型。