《PHP應(yīng)用:PHP內(nèi)核探索之變量》要點:
本文介紹了PHP應(yīng)用:PHP內(nèi)核探索之變量,希望對您有用。如果有疑問,可以聯(lián)系我們。
php變量組成部分:PHP學(xué)習(xí)
變量名:php語言的變量名以$開頭+英文/下劃線,可以包括數(shù)字、下劃線、字母,區(qū)分大小寫.同時PHP也支持復(fù)合變量,形如$$A,增加了php的動態(tài)性.
PHP學(xué)習(xí)
類型:php屬于弱類型語言,可以賦值任意類型的值.PHP學(xué)習(xí)
內(nèi)容:在同一時刻只能有一種值.PHP學(xué)習(xí)
php語言中存在8中數(shù)據(jù)類型,分為三大類: PHP學(xué)習(xí)
1. 標量類型:Boolean,integer,float,string;
PHP學(xué)習(xí)
2. 復(fù)合類型:object,array;
PHP學(xué)習(xí)
3. 特殊類型:NULL,resource;PHP學(xué)習(xí)
php作為一種弱類型語言,在實現(xiàn)內(nèi)部所有變量是通過結(jié)構(gòu)zval來存儲數(shù)據(jù)的,不僅包括變量的值,也包括變量的類型,是php弱類型的核心.
PHP學(xué)習(xí)
zval數(shù)據(jù)布局:PHP學(xué)習(xí)
struct _zval_struct{ zvalue_value value; //存儲變量的值 zend_unint refcount_gc; //引用計數(shù) zend_char is_ref_gc; // 是否為引用 zend_char type; //存儲變量的類型 }
其中zvalue_value并不是一個結(jié)構(gòu)體,為了節(jié)省內(nèi)存使用的union來實現(xiàn)的,因為在同一時刻變量只能表現(xiàn)一種類型.其原型:PHP學(xué)習(xí)
typedef union _zvalue_value{ long lval; double dval; struct { char *val; int len; //字符串的長度 }str; HashTable *ht; //保留數(shù)組 zend_object_value obj; //對象 }zvalue_value;
哈希表:PHP學(xué)習(xí)
php內(nèi)部很多實現(xiàn)基于哈希表:變量的作用域、函數(shù)表、類的屬性、辦法等,Zend引擎內(nèi)部的很多數(shù)據(jù)都是保存在哈希表中的.
PHP學(xué)習(xí)
php數(shù)組使用哈希表來存儲關(guān)聯(lián)數(shù)據(jù),哈希表實現(xiàn)使用兩個數(shù)據(jù)布局HashTable和Bucket:PHP學(xué)習(xí)
HashTable:PHP學(xué)習(xí)
typedef struct _hashtable { uint nTableSize; // hash Bucket的大小,最小為8,以2x增長. uint nTableMask; // nTableSize-1 , 索引取值的優(yōu)化 uint nNumOfElements; // hash Bucket中當前存在的元素個數(shù),count()函數(shù)會直接返回此值 ulong nNextFreeElement; // 下一個數(shù)字索引的位置 Bucket *pInternalPointer; // 當前遍歷的指針(foreach比for快的原因之一) Bucket *pListHead; // 存儲數(shù)組頭元素指針 Bucket *pListTail; // 存儲數(shù)組尾元素指針 Bucket **arBuckets; // 存儲hash數(shù)組 dtor_func_t pDestructor; // 在刪除元素時執(zhí)行的回調(diào)函數(shù),用于資源的釋放 zend_bool persistent; // 指出了Bucket內(nèi)存分配的方式.如果persisient為TRUE, 則使用操作系統(tǒng)本身的內(nèi)存分配函數(shù)為Bucket分配內(nèi)存,否則使用 PHP的內(nèi)存分配函數(shù). unsigned char nApplyCount; // 標記當前hash Bucket被遞歸拜訪的次數(shù)(防止多次遞歸) zend_bool bApplyProtection;// 標記當前hash桶允許不允許多次拜訪,不允許時,最多只能遞歸3次 #if ZEND_DEBUG int inconsistent; #endif } HashTable;
在HashTable中容量的擴增,始終調(diào)整為接近初始大小的2的整數(shù)次方.因為:
PHP學(xué)習(xí)
在選槽時,這里使用&操作而不是使用取模,這是因為是相對來說取模操作的消耗和按位與的操作大很多.mask的作用就是將哈希值映射到槽位所能存儲的索引范圍內(nèi). 例如:某個key的索引值是21, 哈希表的大小為8,則mask為7,則求與時的二進制表示為: 10101 & 111 = 101 也就是十進制的5. 因為2的整數(shù)次方-1的二進制比擬特殊:后面N位的值都是1,這樣比擬容易能將值進行映射, 如果是普通數(shù)字進行了二進制與之后會影響哈希值的結(jié)果.那么哈希函數(shù)計算的值的平均分布就可能出現(xiàn)影響.PHP學(xué)習(xí)
bucket:PHP學(xué)習(xí)
typedef struct bucket { ulong h; // 對char *key進行hash后的值,或者是用戶指定的數(shù)字索引值 uint nKeyLength; // hash關(guān)鍵字的長度,如果數(shù)組索引為數(shù)字,此值為0 void *pData; // 指向value,一般是用戶數(shù)據(jù)的副本,如果是指針數(shù)據(jù),則指向pDataPtr void *pDataPtr; //如果是指針數(shù)據(jù),此值會指向真正的value,同時上面pData會指向此值 struct bucket *pListNext; // 整個hash表的下一元素 struct bucket *pListLast; // 整個哈希表該元素的上一個元素 struct bucket *pNext; // 存放在同一個hash Bucket內(nèi)的下一個元素 struct bucket *pLast; // 同一個哈希bucket的上一個元素 // 保留當前值所對于的key字符串,這個字段只能定義在最后,實現(xiàn)變長結(jié)構(gòu)體 char arKey[1]; } Bucket;
在Bucket中存儲的是哈希值而不是哈希的索引.PHP學(xué)習(xí)
上面結(jié)構(gòu)體的最后一個字段用來保留key的字符串,而這個字段卻申明為只有一個字符的數(shù)組, 其實這里是一種長見的變長結(jié)構(gòu)體,主要的目的是增加靈活性. 以下為哈希表插入新元素時申請空間的代碼PHP學(xué)習(xí)
p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); if (!p) { return FAILURE; } memcpy(p->arKey, arKey, nKeyLength);
插入過程圖PHP學(xué)習(xí)
哈希算法
PHP學(xué)習(xí)
php中hash函數(shù)使用DJBX33A算法來實現(xiàn).PHP學(xué)習(xí)
對象:
PHP學(xué)習(xí)
php對象使用數(shù)據(jù)布局zend_object_value來存儲;PHP學(xué)習(xí)
《PHP應(yīng)用:PHP內(nèi)核探索之變量》是否對您有啟發(fā),歡迎查看更多與《PHP應(yīng)用:PHP內(nèi)核探索之變量》相關(guān)教程,學(xué)精學(xué)透。維易PHP學(xué)院為您提供精彩教程。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/8183.html