原文鏈接:http://www.orlion.ga/238/
編程語言的類型可以分為強類型和弱類型兩種,PHP是弱類型語言,但是C語言是強類型語言。在官網PHP實現內部,所有變量使用同一種數據結構(zval)來保存,這個結構表示PHP中的各種數據類型,它不僅包含變量的值,也包含變量的類型。這就是PHP弱類型的核心。
那zval結構是如何實現弱類型的呢?
一、PHP變量類型及存儲結構
PHP在聲明和使用變量的時候,並不需要指明其數據類型,PHP是弱類型語言,但是PHP有類型,PHP有八中數據類型,可以分成三類:標量類型:boolean、integer、float(double) string;復合類型:array、object;特殊類型:resource、NULL
C語言是如何實現PHP中的弱類型的呢?
1、變量存儲結構
變量的值存儲到如下所示的zval結構體中,zval結構體定義在Zend/zend.h文件,其結構如下:
typedef struct _zval_struct zval; ... struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; zend_uchar type; /* active type */ zend_uchar is_ref__gc; };
zval結構體中有四個字段,其含義分別為:
屬性名 含義 默認值 refcount_gc 表示引用計數 1 is_ref_gc 表示是否為引用 0 value 存儲變量的值 type 變量具體的類型在PHP5.3之後,引入了新的垃圾回收機制,引用計數和引用的字段名改為refcout_gc和is_ref_gc在此之前為refcount和is_ref.
變量的值存儲在另外一個結構體zvalue_value,值存儲見下面的介紹。
2、變量類型
zval結構體的type字段就是實現弱類型最關鍵的字段了,type的值可以為:IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_OBJECT和IS_RESOURCE之一。除此之外和它們定義在一起的類型還有IS_CONSTANT、IS_CONSTANT_ARRAY。
二、變量的值存儲
前面提到變量的值存儲在zvalue_value聯合體中,結構體定義如下:
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;
各種類型的數據會使用不同的方法來進行變量值的存儲,其對應賦值方式如下:
一般類型:
變量類型 宏 boolean ZVAL_BOOL
布爾型/整型的變量值存儲於(zval).value.lval中,其類型也會
以相應的IS_*進行存儲
integer ZVAL_LONG float ZVAL_DOUBLE Z_TYPE_P(z)=IS_BOOL/LONG;Z_LVAL_P(z)=(b)!=0; null ZVAL_NULLNULL值的變量值不需要存儲,只需要把(zval).type標為IS_NUL
Z_TYPE_P(z)=IS_NULL;
resource ZVAL_RESOURCE資源類型的存儲與其他一般變量無異,但其初始化及存儲實現則不
同Z_TYPE_P(z) = IS_RESOURCE; Z_LVAL_P(z) = 1;
字符串
字符串的類型標示和其他數據類型一樣,不過在存儲字符串時多了一個字符串長度的字段。
struct { char *val; int len; } str;
(存儲字符串長度是因為字符串的操作十分頻繁,有利於節省時間,是空間換時間的做法)
數組Array
數組是PHP中最常用也是最強大變量類型。數組的值存儲在zvalue_value.ht字段中,它是一個HashTable類型的數據。PHP數組使用哈希表來存儲關聯數據。PHP的哈希表實現中使用了兩個數據結構HashTable和Bucket。PHP所有的工作都是由哈希表實現。
對象Object
PHP的對象是一種復合型的數據,使用一種zend_object_value的結構體來存放,其定義如下
typedef struct _zend_object_value { zend_object_handle handle; // unsigned int類型,EG(objects_store).object_buckets的索引 zend_object_handlers *handlers; } zend_object_value;
PHP的對象只有在運行時才會被創建,前面介紹了EG宏,這是一個全局結構體由於保存在運行時的數據。其中就包括了用來保存所有被創建的對象的對象池,EG(objects_store),而object對象值內容的zend_object_handle域就是當前對象在對象池中所在的索引,handlers字段則是將對象進行操作時的處理函數保存起來。
PHP的弱變量容器的實現方式是兼容並包的形式體現。