亚洲免费在线视频-亚洲啊v-久久免费精品视频-国产精品va-看片地址-成人在线视频网

您的位置:首頁技術(shù)文章
文章詳情頁

PHP內(nèi)核探索 —— 變量存儲與類型

瀏覽:61日期:2022-09-16 13:53:13

先回答前面一節(jié)的那個問題吧。

<?php$foo = 10;$bar = 20;function change() { global $foo;//echo ’函數(shù)內(nèi)部$foo = ’.$foo.’<br />’;//如果不把$bar定義為global變量,函數(shù)體內(nèi)是不能訪問$bar的 $bar = 0; $foo++;}change();echo $foo, ’ ’, $bar;?>

程序輸出 11 20。原因是,方法內(nèi)部無法訪問$bar變量,所以它的值還是20。使用global之后,可以取得$foo的值,自增后$foo的值就是11。

Global的作用是定義全局變量,但是這個全局變量不是應(yīng)用于整個網(wǎng)站,而是應(yīng)用于當(dāng)前頁面,包括include或require的所有文件。

前言中提到變量的三個基本特性,其中的有一個特性為變量的類型,變量都有特定的類型, 如:字符串、數(shù)組、對象等等。編程語言的類型系統(tǒng)可以分為強類型和弱類型兩種:

強類型語言是一旦某個變量被申明為某個類型的變量,則在程序運行過程中,該不能將該變量的類型以外的值賦予給它 (當(dāng)然并不完全如此,這可能會涉及到類型的轉(zhuǎn)換,后面的小節(jié)會有相應(yīng)介紹),C/C++/Java等語言就屬于這類。

PHP及Ruby,JavaScript等腳本語言屬于弱類型語言:一個變量可以表示任意的數(shù)據(jù)類型。

PHP之所以成為一個簡單而強大的語言,很大一部分的原因是它擁有弱類型的變量。 但是有些時候這也是一把雙刃劍,使用不當(dāng)也會帶來一些問題。就像儀器一樣,越是功能強大, 出現(xiàn)錯誤的可能性也就越大。

在官方的PHP實現(xiàn)內(nèi)部,所有變量使用同一種數(shù)據(jù)結(jié)構(gòu)(zval)來保存,而這個結(jié)構(gòu)同時表示PHP中的各種數(shù)據(jù)類型。 它不僅僅包含變量的值,也包含變量的類型。這就是PHP弱類型的核心。

那zval結(jié)構(gòu)具體是如何實現(xiàn)弱類型的呢,下面我們一起來揭開面紗。

變量存儲結(jié)構(gòu)

PHP在聲明或使用變量的時候,并不需要顯式指明其數(shù)據(jù)類型。

PHP是弱類型語言,這并不表示PHP沒有類型,在PHP中,存在8種變量類型,可以分為三類

* 標(biāo)量類型:boolean、integer、float(double)、string* 復(fù)合類型:?array、object* 特殊類型:?resource、NULL

官方PHP是用C實現(xiàn)的,而C是強類型的語言,那這是怎么實現(xiàn)PHP中的弱類型的呢?

變量的值存儲到以下所示zval結(jié)構(gòu)體中。 zval結(jié)構(gòu)體定義在Zend/zend.h文件,其結(jié)構(gòu)如下:

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使用這個結(jié)構(gòu)來存儲變量的所有數(shù)據(jù)。和其他編譯性靜態(tài)語言不同, PHP在存儲變量時將PHP用戶空間的變量類型也保存在同一個結(jié)構(gòu)體中。這樣我們就能通過這些信息獲取到變量的類型。

zval結(jié)構(gòu)體中有四個字段,其含義分別為:

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

在PHP5.3之后,引入了新的垃圾收集機制,引用計數(shù)和引用的字段名改為refcount__gc和is_ref__gc。在此之前為refcount和is__ref。

而變量的值則存儲在另外一個結(jié)構(gòu)體zvalue_value中。值存儲見下面的介紹。

PHP用戶空間指的在PHP語言這一層面,而本書中大部分地方都在探討PHP的實現(xiàn)。 這些實現(xiàn)可以理解為內(nèi)核空間。由于PHP使用C實現(xiàn),而這個空間的范疇就會限制在C語言。 而PHP用戶空間則會受限于PHP語法及功能提供的范疇之內(nèi)。 例如有些PHP擴展會提供一些PHP函數(shù)或者類,這就是向PHP用戶空間導(dǎo)出了方法或類。

變量類型

zval結(jié)構(gòu)體的type字段就是實現(xiàn)弱類型最關(guān)鍵的字段了,type的值可以為: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一。 從字面上就很好理解,他們只是類型的唯一標(biāo)示,根據(jù)類型的不同將不同的值存儲到value字段。 除此之外,和他們定義在一起的類型還有IS_CONSTANT和IS_CONSTANT_ARRAY。

這和我們設(shè)計數(shù)據(jù)庫時的做法類似,為了避免重復(fù)設(shè)計類似的表,使用一個標(biāo)示字段來記錄不同類型的數(shù)據(jù)。

變量的值存儲

前面提到變量的值存儲在zvalue_value聯(lián)合體中,結(jié)構(gòu)體定義如下:

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;

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

各種類型的數(shù)據(jù)會使用不同的方法來進行變量值的存儲,其對應(yīng)賦值方式如下:

1. 一般類型

變量類型宏?booleanZVAL_BOOL布爾型/整型的變量值存儲于(zval).value.lval中,其類型也會以相應(yīng)的IS_*進行存儲。 Z_TYPE_P(z)=IS_BOOL/LONG; Z_LVAL_P(z)=((b)!=0);integerZVAL_LONGfloatZVAL_DOUBLEnullZVAL_NULLNULL值的變量值不需要存儲,只需要把(zval).type標(biāo)為IS_NULL。 Z_TYPE_P(z)=IS_NULL;resourceZVAL_RESOURCE資源類型的存儲與其他一般變量無異,但其初始化及存取實現(xiàn)則不同。 Z_TYPE_P(z) = IS_RESOURCE; Z_LVAL_P(z) = l;

2. 字符串Sting

字符串的類型標(biāo)示和其他數(shù)據(jù)類型一樣,不過在存儲字符串時多了一個字符串長度的字段。

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

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

3. 數(shù)組Array

數(shù)組是PHP中最常用,也是最強大變量類型,它可以存儲其他類型的數(shù)據(jù),而且提供各種內(nèi)置操作函數(shù)。數(shù)組的存儲相對于其他變量要復(fù)雜一些, 數(shù)組的值存儲在zvalue_value.ht字段中,它是一個HashTable類型的數(shù)據(jù)。 PHP的數(shù)組使用哈希表來存儲關(guān)聯(lián)數(shù)據(jù)。哈希表是一種高效的鍵值對存儲結(jié)構(gòu)。PHP的哈希表實現(xiàn)中使用了兩個數(shù)據(jù)結(jié)構(gòu)HashTable和Bucket。 PHP所有的工作都由哈希表實現(xiàn),在下節(jié)HashTable中將進行哈希表基本概念的介紹以及PHP的哈希表實現(xiàn)。

4. 對象Object

在面向?qū)ο笳Z言中,我們能自己定義自己需要的數(shù)據(jù)類型,包括類的屬性,方法等數(shù)據(jù)。而對象則是類的一個具體實現(xiàn)。 對象有自身的狀態(tài)和所能完成的操作。

PHP的對象是一種復(fù)合型的數(shù)據(jù),使用一種zend_object_value的結(jié)構(gòu)體來存放。其定義如下:

typedef struct _zend_object_value { zend_object_handle handle; // unsigned int類型,EG(objects_store).object_buckets的索引 zend_object_handlers *handlers;} zend_object_value;

PHP的對象只有在運行時才會被創(chuàng)建,前面的章節(jié)介紹了EG宏,這是一個全局結(jié)構(gòu)體用于保存在運行時的數(shù)據(jù)。 其中就包括了用來保存所有被創(chuàng)建的對象的對象池,EG(objects_store),而object對象值內(nèi)容的zend_object_handle域就是當(dāng)前 對象在對象池中所在的索引,handlers字段則是將對象進行操作時的處理函數(shù)保存起來。 這個結(jié)構(gòu)體及對象相關(guān)的類的結(jié)構(gòu)_zend_class_entry,后面會介紹到。

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

PHP主要的用途是作為Web開發(fā)語言,在普通的Web應(yīng)用中瓶頸通常在業(yè)務(wù)和數(shù)據(jù)訪問這一層。不過在大型應(yīng)用下語言也會是一個關(guān)鍵因素。 facebook因此就使用了自己的php實現(xiàn)。將PHP編譯為C++代碼來提高性能。不過facebook的hiphop并不是完整的php實現(xiàn), 由于它是直接將php編譯為C++,有一些PHP的動態(tài)特性比如eval結(jié)構(gòu)就無法實現(xiàn)。當(dāng)然非要實現(xiàn)也是有方法的, hiphop不實現(xiàn)應(yīng)該也是做了一個權(quán)衡。

標(biāo)簽: PHP
相關(guān)文章:
主站蜘蛛池模板: 超级碰碰碰在线观看 | 欧美 自拍 丝袜 亚洲 | 久久欧美久久欧美精品 | 成人高清毛片a | 黄色美女网站免费 | 美国aaaa一级毛片啊 | 日本亚洲欧美国产日韩ay高清 | 国产欧美久久久精品 | 亚洲伊人色综合网站小说 | 全部在线美女网站免费观看 | 国产男女爽爽爽免费视频 | 暴操女人| 国产精品美乳免费看 | 日韩男人的天堂 | 亚洲欧美高清视频 | 亚洲欧美色视频 | 99视频在线播放 | 97视频在线视频 | 色婷婷激婷婷深爱五月老司机 | 国产精品大全国产精品 | 日日干夜夜爽 | 久草 在线| 精品国产亚一区二区三区 | 91精品国产综合成人 | 台湾三级香港三级在线理论 | 韩国在线精品福利视频在线观看 | 欧美日韩在线视频观看 | 男人的天堂高清在线观看 | 国产精品久久久久影院 | 一级做α爱过程免费视频 | 男人天堂网在线观看 | 成人爽a毛片在线视频网站 成人爽爽大片在线观看 | 成人福利网站含羞草 | 精品日韩欧美一区二区三区在线播放 | 全部免费的毛片在线看美国 | 成人久久久观看免费毛片 | 欧美 自拍| 韩国v欧美v亚洲v日本v | 韩国毛片 免费 | 成人午夜毛片在线看 | 国内精品久久久久影院不卡 |