天天看點

PHP7中的資料類型

PHP7中的資料類型

PHP中變量名→zval,變量值→zend_value。其變量記憶體是通過引用計數管理的,在PHP7中引用計數在value結構中。

變量類型:

頭檔案在PHP源碼 /zend/zend_types.h

PHP7中的資料類型

内部實作:

PHP通過zval這個結構體來表示一個變量,而不同類型的變量值則通過zval嵌入的一個人聯合體表示,即zend_value。

PHP7中的資料類型
PHP7中的資料類型

 zend_value是一個聯合體,其代碼如下:

PHP7中的資料類型

ast、ptr、zv這些類型隻給核心自己使用。

字元串:

PHP為字元串單獨定義了一個結構:zend_string。在zend_value中通過str指向具體結構。

PHP7中的資料類型
PHP7中的資料類型
PHP7中的資料類型

存儲字元串内容的val比較特殊。

val并沒有使用char*類型,字元串配置設定時是類似這樣操作的:malloc(sizeof(zend_sting)+字元串長度),就是會多配置設定出一些記憶體來存儲字元串内容,這塊多出來的記憶體起始位置就是val。

這樣做的好處可以省去一次記憶體配置設定(char*),且更有助于記憶體管理。

val中多出來的一個位元組(結構體中為val[1]而不是val[0])用于存儲存儲字元串的最後一個字元"\0"。

 比如$a="abc",則對應的zend_string記憶體結構如左圖:

數組:

PHP7中的資料類型
PHP7中的資料類型

nTableMask:這個值在散列函數根據key的hash code銀蛇元素的存儲為位置時用到。nTableMask = -nTableSize 或 nTableMask  = ~nTableSize+1。

nNumUsed、nNumOfElements:當删除數組元素時并不會立馬從數組中删除,而是将這個元素的類型标為IS_UNDEF,隻有在數組容量超限,需要擴容時才會删除。

若沒有擴容,則nNumUsed将一直遞增,是以其值并不是有效的元素數。nNumOfElements則是數組中有效元素的數量,是以nNumOfElements ≤ nNumUsed。

Bucket結構用力儲存元素的key及value。而h是hash code:如果key是數值(及數值索引)那麼它的值就是數值索引的值;如果key是字元串,那麼它的值就是根據字元串key通過Time33算法計算得到的散列值。h值用來映射元素的存儲位置。

PHP7中的資料類型

數組實作:

為了實作散清單的有序性,PHP中的散清單在散列函數與元素數組之間加了一層映射表,這個映射表也是數組,大小與存儲元素的數組相同。

中間映射表存儲元素在實際存儲的有序數組中的下标:元素按照先後順序依次插入實際存儲數組,然後将其數組下标按照散列函數散列出來的位置存儲在新加的映射表中。

PHP7中的資料類型

散列函數:根據key映射出元素的的存儲位置,通常會以取模作為散列函數:key->h % nTableSize。但PHP采用另一種方式:nIndex = key->h | nTableMask。

在PHP數組的結構中并沒有發現這個中間映射表,事實上,它與arData放在一起。在數組初始化時,同時配置設定用于存儲Bucket的記憶體和配置設定相同數量的uint32_t大小的空間。然後将arData偏移到存儲元素數組的位置。

中間映射表可以通過arData向前通路到。

PHP7中的資料類型

哈希沖突:不同的key值可能計算得到相同的哈希值,在插入散清單時會發生沖突,因為映射表隻能存儲一個元素。

解決方法:把沖突的Bucket串成連結清單,即中間映射表映射出來的是一個Bucket連結清單,而不是一個Bucket,查找時需要周遊這個連結清單,逐個比較key,進而找到目标元素。

HashTable會記錄與它沖突的元素在arData數組中的存儲位置。

PHP7中的資料類型

 在設定映射值時,發現中間映射表中要設定的位置已經被之前插入的元素占用了(值不等于初始化的-1),那麼會把已經存在的值儲存到新插入的Bucket中(即c插入後u2.next=0),然後将映射表中的值更新為新Bucket的存儲位置(即映射表中的值:2)。

引用:

引用是一種指向其他類型的結構,類似C語言中指針的概念。當修改引用類型的變量時,其修改将反應到實際引用的變量上。

在PHP中通過&操作符生成一個引用變量,比如$b = &$a,執行時首先為&操作的變量配置設定一個zend_reference結構,這個結構就是引用類型的結構體,它内嵌了一個zval,此zval的value指向原來zval的value,然後将原zval的類型修改為IS_REFERENCE,原zval的value指向新建立的zend_reference結構。

PHP7中的資料類型
PHP7中的資料類型

例子:

$a = date("Y-m");
$b = &$a;      

$a為字元串,通過&$a将其轉化為引用類型并指派給了$b,轉換後的$a的類型由IS_STRING變為IS_REFERENCE,$a的value也轉變為zend_reference結構,這個結構指向原來的字元串。

$a、$b間接指向了實際的value值。 

PHP7中的資料類型

使用引用時需要注意,引用隻能通過&産生,不能通過指派傳遞。

如上面的例子,再把$b指派給其他變量,那麼傳遞給新變量的value将是實際引用的值,而不是引用本身。

$a = date("Y-m");
$b = &$a;
$c = $b;   //如果想讓$c也引用指向$a/$b引用的值,則:$c = &$b      
PHP7中的資料類型

原文位址

https://www.cnblogs.com/jiangml/p/10478132.html