天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

PHP內(nèi)核介紹及擴(kuò)展開發(fā)指南―基礎(chǔ)知識

一、 基礎(chǔ)知識
  本章簡要介紹一些Zend引擎的內(nèi)部機(jī)制,這些知識和Extensions密切相關(guān),同時(shí)也可以幫助我們寫出更加高效的php代碼。
  1.1 php變量的存儲
  1.1.1 zval結(jié)構(gòu)
  Zend使用zval結(jié)構(gòu)來存儲php變量的值,該結(jié)構(gòu)如下所示:
復(fù)制代碼 代碼如下:
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;
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount;
zend_uchar type; /* active type */
zend_uchar is_ref;
};
typedef struct _zval_struct zval;
<span id="more-597"></span>Zend根據(jù)type值來決定訪問value的哪個(gè)成員,可用值如下:

IS_NULLN/A

  IS_LONG對應(yīng)value.lval

  IS_DOUBLE對應(yīng)value.dval

  IS_STRING對應(yīng)value.str

  IS_ARRAY對應(yīng)value.ht

  IS_OBJECT對應(yīng)value.obj

  IS_BOOL對應(yīng)value.lval.

  IS_RESOURCE對應(yīng)value.lval

  根據(jù)這個(gè)表格可以發(fā)現(xiàn)兩個(gè)有意思的地方:首先是php的數(shù)組其實(shí)就是一個(gè)HashTable,這就解釋了為什么php能夠支持關(guān)聯(lián)數(shù)組了;其次,Resource就是一個(gè)long值,它里面存放的通常是個(gè)指針、一個(gè)內(nèi)部數(shù)組的index或者其它什么只有創(chuàng)建者自己才知道的東西,可以將其視作一個(gè)handle

  1.1.1 引用計(jì)數(shù)

  引用計(jì)數(shù)在垃圾收集、內(nèi)存池以及字符串等地方應(yīng)用廣泛,Zend就實(shí)現(xiàn)了典型的引用計(jì)數(shù)。多個(gè)php變量可以通過引用計(jì)數(shù)機(jī)制來共享同一份zval,zval中剩余的兩個(gè)成員is_ref和refcount就用來支持這種共享。

  很明顯,refcount用于計(jì)數(shù),當(dāng)增減引用時(shí),這個(gè)值也相應(yīng)的遞增和遞減,一旦減到零,Zend就會(huì)回收該zval。

  那么is_ref呢?

  1.1.2 zval狀態(tài)

  在php中,變量有兩種――引用和非引用的,它們在Zend中都是采用引用計(jì)數(shù)的方式存儲的。對于非引用型變量,要求變量間互不相干,修改一個(gè)變量時(shí),不能影響到其他變量,采用Copy-On-Write機(jī)制即可解決這種沖突――當(dāng)試圖寫入一個(gè)變量時(shí),Zend若發(fā)現(xiàn)該變量指向的zval被多個(gè)變量共享,則為其復(fù)制一份refcount為1的zval,并遞減原zval的refcount,這個(gè)過程稱為“zval分離”。然而,對于引用型變量,其要求和非引用型相反,引用賦值的變量間必須是捆綁的,修改一個(gè)變量就修改了所有捆綁變量。

  可見,有必要指出當(dāng)前zval的狀態(tài),以分別應(yīng)對這兩種情況,is_ref就是這個(gè)目的,它指出了當(dāng)前所有指向該zval的變量是否是采用引用賦值的――要么全是引用,要么全不是。此時(shí)再修改一個(gè)變量,只有當(dāng)發(fā)現(xiàn)其zval的is_ref為0,即非引用時(shí),Zend才會(huì)執(zhí)行Copy-On-Write。

  1.1.3 zval狀態(tài)切換

  當(dāng)在一個(gè)zval上進(jìn)行的所有賦值操作都是引用或者都是非引用時(shí),一個(gè)is_ref就足夠應(yīng)付了。然而,世界總不會(huì)那么美好,php無法對用戶進(jìn)行這種限制,當(dāng)我們混合使用引用和非引用賦值時(shí),就必須要進(jìn)行特別處理了。

  情況I、看如下php代碼:

<!--p $a = 1; $b = &$a; $c = &$b; $d = $c; // 在一堆引用賦值中,插入一個(gè)非引用-->



  全過程如下所示:

  這段代碼的前三句將把a(bǔ)、b和c指向一個(gè)zval,其is_ref=1, refcount=3;第四句是個(gè)非引用賦值,通常情況下只需要增加引用計(jì)數(shù)即可,然而目標(biāo)zval屬于引用變量,單純的增加引用計(jì)數(shù)顯然是錯(cuò)誤的, Zend的解決辦法是為d單獨(dú)生成一份zval副本。

  全過程如下所示:

1.1.1 參數(shù)傳遞

  php函數(shù)參數(shù)的傳遞和變量賦值是一樣的,非引用傳遞相當(dāng)于非引用賦值,引用傳遞相當(dāng)于引用賦值,并且也有可能會(huì)導(dǎo)致執(zhí)行zval狀態(tài)切換。這在后面還將提到。

  1.2 HashTable結(jié)構(gòu)

  HashTable是Zend引擎中最重要、使用最廣泛的數(shù)據(jù)結(jié)構(gòu),它被用來存儲幾乎所有的東西。

  1.1.1 數(shù)據(jù)結(jié)構(gòu)

  HashTable數(shù)據(jù)結(jié)構(gòu)定義如下:
復(fù)制代碼 代碼如下:
typedef struct bucket {
ulong h; // 存放hash
uint nKeyLength;
void *pData; // 指向value,是用戶數(shù)據(jù)的副本
void *pDataPtr;
struct bucket *pListNext; // pListNext和pListLast組成
struct bucket *pListLast; // 整個(gè)HashTable的雙鏈表
struct bucket *pNext; // pNext和pLast用于組成某個(gè)hash對應(yīng)
struct bucket *pLast; // 的雙鏈表
char arKey[1]; // key
} Bucket;
typedef struct _hashtable {
uint nTableSize;
uint nTableMask;
uint nNumOfElements;
ulong nNextFreeElement;
Bucket *pInternalPointer; /* Used for element traversal */
Bucket *pListHead;
Bucket *pListTail;
Bucket **arBuckets; // hash數(shù)組
dtor_func_t pDestructor; // HashTable初始化時(shí)指定,銷毀Bucket時(shí)調(diào)用
zend_bool persistent; // 是否采用C的內(nèi)存分配例程
unsigned char nApplyCount;
zend_bool bApplyProtection;
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;

總的來說,Zend的HashTable是一種鏈表散列,同時(shí)也為線性遍歷進(jìn)行了優(yōu)化,圖示如下:


HashTable中包含兩種數(shù)據(jù)結(jié)構(gòu),一個(gè)鏈表散列和一個(gè)雙向鏈表,前者用于進(jìn)行快速鍵-值查詢,后者方便線性遍歷和排序,一個(gè)Bucket同時(shí)存在于這兩個(gè)數(shù)據(jù)結(jié)構(gòu)中。
  關(guān)于該數(shù)據(jù)結(jié)構(gòu)的幾點(diǎn)解釋:
  l 鏈表散列中為什么使用雙向鏈表?
  一般的鏈表散列只需要按key進(jìn)行操作,只需要單鏈表就夠了。但是,Zend有時(shí)需要從鏈表散列中刪除給定的Bucket,使用雙鏈表可以非常高效的實(shí)現(xiàn)。
  l nTableMask是干什么的?
  這個(gè)值用于hash值到arBuckets數(shù)組下標(biāo)的轉(zhuǎn)換。當(dāng)初始化一個(gè)HashTable,Zend首先為arBuckets數(shù)組分配nTableSize大小的內(nèi)存,nTableSize取不小于用戶指定大小的最小的2^n,即二進(jìn)制的10*。nTableMask = nTableSize 主站蜘蛛池模板: 久久性生大片免费观看性 | 国产欧美精品国产国产专区 | 日本精油按摩 | 亚洲 日本 欧美 中文字幕 | 大香交伊人 | 97午夜伦伦电影理论片 | 男人吃奶摸下弄进去好爽 | 日本十八禁无遮拦啪啪漫画 | 国产在线精品视亚洲不卡 | 99在线观看视频免费 | 最新老头恋老OLDMAN | 久久免费高清 | 日韩亚洲欧洲在线rrrr片 | 亚洲综合国产在不卡在线 | 国产乱码精品一区二区三区四川 | 亚洲 欧美 中文 日韩 另类 | 亚洲三级在线中文字幕 | 国产对白精品刺激一区二区 | 在线视频免费国产成人 | 国产成人无码精品久久久按摩 | 野草视频在线观看 | 91嫩草国产在线观看免费 | 久久精品国产午夜伦班片 | 亚洲精品久久久午夜福利电影网 | 国产精品久久久久成人免费 | 沈芯语麻豆0076 视频 | 日韩做A爰片久久毛片A片毛茸茸 | 蜜桃视频无码区在线观看 | 久久综合九色 | 天天靠天天擦天天摸 | 亚洲色欲色欲WWW在线成人网 | 男女性杂交内射妇女BBWXZ | 国产乱码二卡3卡四卡 | 憋尿调教绝望之岛 | 青青app | 久久久精品国产免费A片胖妇女 | 午夜伦理电影在线观免费 | 96精品视频 | 国产成人精品男人的天堂网站 | 大桥未久在线看 | www.av日韩|