摘要:對于來說,變量有全局變量和局部變量之分那么,他們都是存儲到一個哈希表內(nèi)了么其實不是的,變量存儲也有作用域的概念。
上次跟大家講了垃圾回收機制后,有些小伙伴對底層原理比較感興趣,私信問我了一些關于變量的相關知識,既然大家對變量比較感興趣,那么這次我們來系統(tǒng)的講一下變量的底層原理
變量結構首先,我們還是先擺上我們的zval結構體,即php所有變量都會以zval結構體的形式實現(xiàn)
struct _zval_struct { union { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; zend_object_value obj; } value; //變量value值 zend_uint refcount__gc; //引用計數(shù)內(nèi)存中使用次數(shù),為0刪除該變量 zend_uchar type; //變量類型 zend_uchar is_ref__gc; //區(qū)分是否是引用變量,是引用為1,否則為0 };
從上面結構體內(nèi)容可以看出每一個php變量都會由變量類型、value值、引用計數(shù)次數(shù)和是否是引用變量四部分組成
注:上面zval結構體是php5.3版本之后,php7版本之前的結構
變量類型看到這里,可能會有小伙伴們問我,php不是有8種數(shù)據(jù)類型嗎?但是為什么對應的zvalue的value值只有5種?
原因是這樣的,php出于對內(nèi)存節(jié)省的考慮,所以對于一些變量類型做了復用,并沒有一一對應去定義每個變量類型
下面我們看一下zvalue的每個value值所對應的變量類型
zval.value.lval => 整型、布爾型、資源 zval.value.dval => 浮點型 zval.value.str => 字符串 zval.value.*ht => 數(shù)組 zval.value.obj => 對象
看到這里大家可能會比較奇怪,布爾型和資源是怎么對應到zval.value的lval上的呢?還有,NULL呢?
布爾型就像我們會將true和false映射成0和1進行數(shù)據(jù)庫存儲一樣,php也是這么做的。所以php發(fā)現(xiàn)zval的type值是布爾型時,會將布爾型轉(zhuǎn)成0或1存儲在zval.value的lval中
資源資源對于php來說屬于一個比較特殊的變量,而php會將每個資源對應的資源標識存儲在zval.value的lval中。常見的資源有:文件句柄、數(shù)據(jù)庫句柄等
NULL對于NULL來說,就更好理解了,因為本身通過zval的type值即可區(qū)分,所以并沒有將NULL值存儲在zval的value中
變量生成php作為一門動態(tài)語言,沒有先聲明變量后賦值的習慣,所以都是拿來一個變量直接就進行了賦值,那么是如何實現(xiàn)的呢?
舉例:
$name = "許錚的技術成長之路";變量容器生成
其實每次變量被常量賦值時,都會對應生成一個變量容器。剛才的例子會生成一個變量容器,容器的type是字符串類型,而value值則是許錚的技術成長之路,且此時該變量容器的ref_count會加1
變量名和變量容器關聯(lián)而變量name是如何與變量容器關聯(lián)起來的呢?其實也是使用了php的一個內(nèi)部機制,即哈希表。每個變量的變量名和指向zval結構的指針被存儲在哈希表內(nèi),以此實現(xiàn)了變量名到變量容器的映射
變量作用域上面我們提到了變量名和變量容器映射的概念。對于php來說,變量有全局變量和局部變量之分;那么,他們都是存儲到一個哈希表內(nèi)了么?
其實不是的,變量存儲也有作用域的概念。全局變量被存儲到了全局符號表內(nèi),而局部變量也就是指函數(shù)或?qū)ο髢?nèi)的變量,則被存儲到了活動符號表內(nèi)(每個函數(shù)或?qū)ο蠖级鄮ЬS護了自己的活動符號表?;顒臃柋淼纳芷?,從函數(shù)或?qū)ο蟊徽{(diào)用時開始,到調(diào)用完成時結束)
變量銷毀變量銷毀,分為以下幾種情況:
1、手動銷毀
2、垃圾回收機制銷毀(引用計數(shù)清0銷毀和根緩沖區(qū)滿后銷毀)
我們這次主要講一下手動銷毀,即unset,每次銷毀時都會將符號表內(nèi)的變量名和對應的zval結構進行銷毀,并將對應的內(nèi)存歸還到php所維護的內(nèi)存池內(nèi)(按內(nèi)存大小劃分到對應內(nèi)存列表中)
而對于垃圾回收機制的銷毀,如果你不了解其相關原理,那么我建議你看下我之前寫的文章php底層原理之垃圾回收機制
思考今天,我們從底層的角度,將變量從生成到銷毀講了一遍。對于變量的生成,我們是拿常量賦值作為示例講解的,那么變量之間的賦值呢?是什么原理呢?且聽下回分解~
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/31041.html
摘要:但是對于結構體中的和字段我們一直都沒有詳細介紹過,而這兩個字段其實是和變量之間賦值的原理有著密切的關系的。 上周我們從底層的角度介紹了php變量從生成->常量賦值->銷毀的完整生命周期(不了解的同學可以翻看一下前面的文章php底層原理之變量(一)),但是我們留了一個思考,不知道大家有答案了沒,變量之間的賦值在底層又是如何實現(xiàn)的呢? 變量之間賦值 php變量的zval結構,我們已經(jīng)介紹了...
摘要:數(shù)組是最常用的數(shù)據(jù)類型,同時容易上手也得益于其強大的數(shù)組,但是數(shù)組在中是如何實現(xiàn)的呢首先,我們還是先了解下相關的數(shù)據(jù)結構,為下面的內(nèi)容打好基礎哈希表哈希表,顧名思義,即將不同的關鍵字映射到不同單元的一種數(shù)據(jù)結構。 數(shù)組是PHPer最常用的數(shù)據(jù)類型,同時php容易上手也得益于其強大的數(shù)組,但是數(shù)組在php中是如何實現(xiàn)的呢? 首先,我們還是先了解下相關的數(shù)據(jù)結構,為下面的內(nèi)容打好基礎 哈希...
摘要:總結垃圾回收機制以的引用計數(shù)機制為基礎以前只有該機制同時使用根緩沖區(qū)機制,當發(fā)現(xiàn)有存在循環(huán)引用的時,就會把其投入到根緩沖區(qū),當根緩沖區(qū)達到配置文件中的指定數(shù)量后,就會進行垃圾回收,以此解決循環(huán)引用導致的內(nèi)存泄漏問題開始引入該機制 php垃圾回收機制,對于PHPer來說是一個不陌生但是又不是很熟悉的內(nèi)容。那么php是怎么實現(xiàn)對不需要的內(nèi)存進行回收的呢? php變量的內(nèi)部存儲結構 首先還是...
摘要:所以想要理解更深入的同學最好查看下我之前的關于介紹變量函數(shù)的文章類的數(shù)據(jù)結構不管是普通類還是抽象類或是接口,都存放到統(tǒng)一的結構體中,并且在生成中間代碼時,會將此類添加到全局類列表中。 對于PHPer來說,OOP是不可或缺的開發(fā)思維,但是你對php類和對象的底層實現(xiàn)又了解多少呢?本著知其然且知其所以然的思想,讓我們一起來尋找答案~ 類的底層實現(xiàn)可看作是之前我們講過的變量、函數(shù)等的知識集合...
摘要:發(fā)現(xiàn)挺有意思的一個問題,內(nèi)存溢出導致腳本執(zhí)行失敗。那就一起來看個究竟吧首先查看了計劃任務的從報錯信息字面意思可以看出,允許的的內(nèi)存已經(jīng)用盡,還要試圖分配內(nèi)存。給你當前腳本分配的內(nèi)存你已經(jīng)用完了,你還想問系統(tǒng)要內(nèi)存。 今天上午剛到公司,就有同事在公司群里反映某個計劃任務出現(xiàn)問題了。我就懷著刨根問底的心,去查看了log。發(fā)現(xiàn)挺有意思的一個問題,PHP內(nèi)存溢出導致腳本執(zhí)行失敗。那就一起來看個...
閱讀 723·2021-10-14 09:42
閱讀 1976·2021-09-22 15:04
閱讀 1585·2019-08-30 12:44
閱讀 2146·2019-08-29 13:29
閱讀 2738·2019-08-29 12:51
閱讀 556·2019-08-26 18:18
閱讀 707·2019-08-26 13:43
閱讀 2818·2019-08-26 13:38