php中弱語言類型的底層實現


PHP是弱語言類型,主要分為三類:

1、標量類型:integer、string、float、boolean

2、復合類型:array、object

3、特殊類型:resource、null

 

php是通過c語言進行實現,但是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; };

PHP使用這個結構來存儲變量的所有數據。和其他編譯性靜態語言不同, PHP在存儲變量時將PHP用戶空間的變量類型也保存在同一個結構體中。這樣我們就能通過這些信息獲取到變量的類型。

zval結構體中有四個字段,其含義分別為:

屬性名 含義 默認值
refcount__gc 表示引用計數 1
is_ref__gc 表示是否為引用 0
value 存儲變量的值  
type 變量具體的類型  

 

2.變量類型:

zval結構體的type字段就是實現弱類型最關鍵的字段了,type的值可以為: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一。 從字面上就很好理解,他們只是類型的唯一標示,根據類型的不同將不同的值存儲到value字段。 除此之外,和他們定義在一起的類型還有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;

這里使用聯合體而不是用結構體是出於空間利用率的考慮,因為一個變量同時只能屬於一種類型。 如果使用結構體的話將會不必要的浪費空間,而PHP中的所有邏輯都圍繞變量來進行的,這樣的話, 內存浪費將是十分大的。這種做法成本小但收益非常大。

各種類型的數據會使用不同的方法來進行變量值的存儲,其對應賦值方式如下:

  • 一般類型
變量類型  
boolean ZVAL_BOOL 布爾型/整型的變量值存儲於(zval).value.lval中,其類型也會以相應的IS_*進行存儲。
 Z_TYPE_P(z)=IS_BOOL/LONG;  Z_LVAL_P(z)=((b)!=0); 
integer ZVAL_LONG
float ZVAL_DOUBLE
null ZVAL_NULL NULL值的變量值不需要存儲,只需要把(zval).type標為IS_NULL。
 Z_TYPE_P(z)=IS_NULL; 
resource ZVAL_RESOURCE 資源類型的存儲與其他一般變量無異,但其初始化及存取實現則不同。
 Z_TYPE_P(z) = IS_RESOURCE;  Z_LVAL_P(z) = l; 
  • 字符串String

字符串的類型標示和其他數據類型一樣,不過在存儲字符串時多了一個字符串長度的字段。

struct { char *val; int len; } str;

C中字符串是以\0結尾的字符數組,這里多存儲了字符串的長度,這和我們在設計數據庫時增加的冗余字段異曲同工。 因為要實時獲取到字符串的長度的時間復雜度是O(n),而字符串的操作在PHP中是非常頻繁的,這樣能避免重復計算字符串的長度, 這能節省大量的時間,是空間換時間的做法。 
這么看在PHP中strlen()函數可以在常數時間內獲取到字符串的長度。 計算機語言中字符串的操作都非常之多,所以大部分高級語言中都會存儲字符串的長度。

  • 數組Array

數組是PHP中最常用,也是最強大變量類型,它可以存儲其他類型的數據,而且提供各種內置操作函數。數組的存儲相對於其他變量要復雜一些, 數組的值存儲在zvalue_value.ht字段中,它是一個HashTable類型的數據。 PHP的數組使用哈希表來存儲關聯數據。哈希表是一種高效的鍵值對存儲結構。PHP的哈希表實現中使用了兩個數據結構HashTable和Bucket。 PHP所有的工作都由哈希表實現,在下節HashTable中將進行哈希表基本概念的介紹以及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字段則是將對象進行操作時的處理函數保存起來。 這個結構體及對象相關的類的結構_zend_class_entry,將在第五章作詳細介紹。

PHP的弱變量容器的實現方式是兼容並包的形式體現,針對每種類型的變量都有其對應的標記和存儲空間。 使用強類型的語言在效率上通常會比弱類型高,因為很多信息能在運行之前就能確定,這也能幫助排除程序錯誤。 而這帶來的問題是編寫代碼相對會受制約。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM