您好,登錄后才能下訂單哦!
小編給大家分享一下PHP7中的數(shù)據(jù)類(lèi)型有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
PHP中變量名→zval,變量值→zend_value。其變量?jī)?nèi)存是通過(guò)引用計(jì)數(shù)管理的,在PHP7中引用計(jì)數(shù)在value結(jié)構(gòu)中。
頭文件在PHP源碼 /zend/zend_types.h
PHP通過(guò)zval這個(gè)結(jié)構(gòu)體來(lái)表示一個(gè)變量,而不同類(lèi)型的變量值則通過(guò)zval嵌入的一個(gè)人聯(lián)合體表示,即zend_value。
zend_value是一個(gè)聯(lián)合體,其代碼如下:
ast、ptr、zv這些類(lèi)型只給內(nèi)核自己使用。
PHP為字符串單獨(dú)定義了一個(gè)結(jié)構(gòu):zend_string。在zend_value中通過(guò)str指向具體結(jié)構(gòu)。
存儲(chǔ)字符串內(nèi)容的val比較特殊。
val并沒(méi)有使用char*類(lèi)型,字符串分配時(shí)是類(lèi)似這樣操作的:malloc(sizeof(zend_sting)+字符串長(zhǎng)度),就是會(huì)多分配出一些內(nèi)存來(lái)存儲(chǔ)字符串內(nèi)容,這塊多出來(lái)的內(nèi)存起始位置就是val。
這樣做的好處可以省去一次內(nèi)存分配(char*),且更有助于內(nèi)存管理。
val中多出來(lái)的一個(gè)字節(jié)(結(jié)構(gòu)體中為val[1]而不是val[0])用于存儲(chǔ)存儲(chǔ)字符串的最后一個(gè)字符"\0"。
比如$a="abc",則對(duì)應(yīng)的zend_string內(nèi)存結(jié)構(gòu)如左圖:
nTableMask:這個(gè)值在散列函數(shù)根據(jù)key的hash code銀蛇元素的存儲(chǔ)為位置時(shí)用到。nTableMask = -nTableSize 或 nTableMask = ~nTableSize+1。
nNumUsed、nNumOfElements:當(dāng)刪除數(shù)組元素時(shí)并不會(huì)立馬從數(shù)組中刪除,而是將這個(gè)元素的類(lèi)型標(biāo)為IS_UNDEF,只有在數(shù)組容量超限,需要擴(kuò)容時(shí)才會(huì)刪除。
若沒(méi)有擴(kuò)容,則nNumUsed將一直遞增,所以其值并不是有效的元素?cái)?shù)。nNumOfElements則是數(shù)組中有效元素的數(shù)量,所以nNumOfElements ≤ nNumUsed。
Bucket結(jié)構(gòu)用力保存元素的key及value。而h是hash code:如果key是數(shù)值(及數(shù)值索引)那么它的值就是數(shù)值索引的值;如果key是字符串,那么它的值就是根據(jù)字符串key通過(guò)Time33算法計(jì)算得到的散列值。h值用來(lái)映射元素的存儲(chǔ)位置。
數(shù)組實(shí)現(xiàn):
為了實(shí)現(xiàn)散列表的有序性,PHP中的散列表在散列函數(shù)與元素?cái)?shù)組之間加了一層映射表,這個(gè)映射表也是數(shù)組,大小與存儲(chǔ)元素的數(shù)組相同。
中間映射表存儲(chǔ)元素在實(shí)際存儲(chǔ)的有序數(shù)組中的下標(biāo):元素按照先后順序依次插入實(shí)際存儲(chǔ)數(shù)組,然后將其數(shù)組下標(biāo)按照散列函數(shù)散列出來(lái)的位置存儲(chǔ)在新加的映射表中。
散列函數(shù):根據(jù)key映射出元素的的存儲(chǔ)位置,通常會(huì)以取模作為散列函數(shù):key->h % nTableSize。但PHP采用另一種方式:nIndex = key->h | nTableMask。
在PHP數(shù)組的結(jié)構(gòu)中并沒(méi)有發(fā)現(xiàn)這個(gè)中間映射表,事實(shí)上,它與arData放在一起。在數(shù)組初始化時(shí),同時(shí)分配用于存儲(chǔ)Bucket的內(nèi)存和分配相同數(shù)量的uint32_t大小的空間。然后將arData偏移到存儲(chǔ)元素?cái)?shù)組的位置。
中間映射表可以通過(guò)arData向前訪問(wèn)到。
哈希沖突:不同的key值可能計(jì)算得到相同的哈希值,在插入散列表時(shí)會(huì)發(fā)生沖突,因?yàn)橛成浔碇荒艽鎯?chǔ)一個(gè)元素。
解決方法:把沖突的Bucket串成鏈表,即中間映射表映射出來(lái)的是一個(gè)Bucket鏈表,而不是一個(gè)Bucket,查找時(shí)需要遍歷這個(gè)鏈表,逐個(gè)比較key,從而找到目標(biāo)元素。
HashTable會(huì)記錄與它沖突的元素在arData數(shù)組中的存儲(chǔ)位置。
在設(shè)置映射值時(shí),發(fā)現(xiàn)中間映射表中要設(shè)置的位置已經(jīng)被之前插入的元素占用了(值不等于初始化的-1),那么會(huì)把已經(jīng)存在的值保存到新插入的Bucket中(即c插入后u2.next=0),然后將映射表中的值更新為新Bucket的存儲(chǔ)位置(即映射表中的值:2)。
引用是一種指向其他類(lèi)型的結(jié)構(gòu),類(lèi)似C語(yǔ)言中指針的概念。當(dāng)修改引用類(lèi)型的變量時(shí),其修改將反應(yīng)到實(shí)際引用的變量上。
在PHP中通過(guò)&操作符生成一個(gè)引用變量,比如$b = &$a,執(zhí)行時(shí)首先為&操作的變量分配一個(gè)zend_reference結(jié)構(gòu),這個(gè)結(jié)構(gòu)就是引用類(lèi)型的結(jié)構(gòu)體,它內(nèi)嵌了一個(gè)zval,此zval的value指向原來(lái)zval的value,然后將原zval的類(lèi)型修改為IS_REFERENCE,原zval的value指向新創(chuàng)建的zend_reference結(jié)構(gòu)。
例子:
$a = date("Y-m");$b = &$a;
$a為字符串,通過(guò)&$a將其轉(zhuǎn)化為引用類(lèi)型并賦值給了$b,轉(zhuǎn)換后的$a的類(lèi)型由IS_STRING變?yōu)镮S_REFERENCE,$a的value也轉(zhuǎn)變?yōu)閦end_reference結(jié)構(gòu),這個(gè)結(jié)構(gòu)指向原來(lái)的字符串。
$a、$b間接指向了實(shí)際的value值。
使用引用時(shí)需要注意,引用只能通過(guò)&產(chǎn)生,不能通過(guò)賦值傳遞。
如上面的例子,再把$b賦值給其他變量,那么傳遞給新變量的value將是實(shí)際引用的值,而不是引用本身。
$a = date("Y-m");$b = &$a;$c = $b; //如果想讓$c也引用指向$a/$b引用的值,則:$c = &$b
以上是“PHP7中的數(shù)據(jù)類(lèi)型有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。