本篇文章的內容介紹的是關於PHP7核心剖析1之CGI與FastCGI ,現在分享給大家,有需要的朋友可以參考一下
1.變數結構
typedef struct _zval_struct zval; typedef union _zend_value { zend_long lval; //int整形 double dval; //浮点型 zend_string *str; //string字符串 zend_array *arr; //array数组 zend_object *obj; //object对象 zend_resource *res; //resource资源类型 zend_reference *ref; //引用类型,通过&$var_name定义的 } zend_value; struct _zval_struct { zend_value value; //变量实际的value union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, //变量类型 zend_uchar type_flags, //类型掩码,不同的类型会有不同的几种属性,内存管理会用到 zend_uchar const_flags, zend_uchar reserved) } v; uint32_t type_info; //上面4个值的组合值,可以直接根据type_info取到4个对应位置的值 } u1; union { uint32_t var_flags; uint32_t next; //哈希表中解决哈希冲突时用到 uint32_t cache_slot; uint32_t lineno; uint32_t num_args; uint32_t fe_pos; uint32_t fe_iter_idx; } u2; };
2.變數類型
#define IS_UNDEF 0 #define IS_NULL 1 #define IS_FALSE 2 #define IS_TRUE 3 #define IS_LONG 4 #define IS_DOUBLE 5 #define IS_STRING 6 #define IS_ARRAY 7 #define IS_OBJECT 8 #define IS_RESOURCE 9 #define IS_REFERENCE 10
其中undef、true、false、null沒有value,直接依照type區分,而long 、double的值則直接存在value中,其他型別為指標
#3.字串##
typedef struct _zend_string zend_string; struct _zend_string { zend_refcounted_h gc; //变量引用信息,比如当前value的引用数 size_t len; //字符串长度,通过这个值保证二进制安全 char val[1]; //字符串内容,变长struct,分配时按len长度申请内存 };
4.陣列
typedef struct _zend_array HashTable; typedef struct _zend_array zend_array; typedef struct _Bucket { zval val; //存储的具体value,这里嵌入了一个zval,而不是一个指针 zend_ulong h; //哈希值 zend_string *key; //key值 } Bucket; struct _zend_array { zend_refcounted_h gc; //引用计数信息 uint32_t nTableMask; //计算bucket索引时的掩码,用于散列表的计算nIndex Bucket *arData; //bucket数组 uint32_t nNumUsed; //已用bucket数 uint32_t nNumOfElements; //已有元素数,nNumOfElements <= nNumUsed,因为删除的并不是直接从arData中移除 uint32_t nTableSize; //数组的大小,为2^n,默认为8 uint32_t nInternalPointer; //数值索引,用于HashTable遍历 zend_long nNextFreeElement;//下一个空闲可用位置的数字索引 dtor_func_t pDestructor;//析构函数,销毁时调用的函数指针 };HashTable主要依賴arData實作元素的儲存、索引。插入一個元素時先將元素依先後順序插入Bucket數組,位置是idx,再根據key的雜湊值映射到散列表中的某個位置nIndex,將idx存入這個位置;查找時先在散列表中映射到nIndex,得到value在Bucket數組的位置idx,再從Bucket數組中取出元素。
$arr["a"] = 1; $arr["b"] = 2; $arr["c"] = 3; $arr["d"] = 4; unset($arr["c"]);
哈希碰撞:當發生衝突時將原value的位置儲存到新value的zval.u2.next中,然後將新value代替原value位置擴容:PHP散列表的大小為2^n,插入時如果容量不夠則首先檢查已刪除元素所佔比例,如果達到閾值,則將已刪除元素移除,重建索引,如果未到閾值則進行擴容操作,擴大為目前大小的2倍,將目前Bucket數組複製到新的空間,然後重建索引。 重建散列表:當刪除元素達到一定數量或擴容後都需要重建散列表,因為value在Bucket位置移動了或哈希數組nTableSize變化了導致key與value的映射關係改變,重建過程實際上就是遍歷Bucket數組中的value,然後重新計算映射值更新到散列表,移除已刪除的value,將後面未刪除的value依次前移
5.引用
引用是PHP中比較特殊的一種類型,它實際上是指向另外一個PHP變量,對它的修改會直接改動實際指向的zval,可以簡單的理解為C中的指針,在PHP中透過&運算子產生一個引用變量,也就是說不管以前的型別是什麼,&首先會建立一個zend_reference結構,其內嵌了一個zval,這個zval的value指向原來zval的value(如果是布林、整形、浮點則直接複製原來的值),然後將原zval的型別修改為IS_REFERENCE,原zval的value指向新建立的zend_reference結構。typedef struct _zend_reference zend_reference; struct _zend_reference { zend_refcounted_h gc; zval val; };
6.引用計數#
typedef struct _zend_refcounted_h { uint32_t refcount; union { struct { ZEND_ENDIAN_LOHI_3( zend_uchar type, zend_uchar flags, uint16_t gc_info) } v; uint32_t type_info; } u; } zend_refcounted_h;
$a = "time:" . time(); //$a -> zend_string_1(refcount=1) $b = $a; //$a,$b -> zend_string_1(refcount=2) $c = $b; //$a,$b,$c -> zend_string_1(refcount=3) unset($b); //$b = IS_UNDEF $a,$c -> zend_string_1(refcount=2)並不是所有的資料型別都會用到引用計數,long、double直接都是硬拷貝,只有value是指標的那幾種型別(除interned string,immutable array)才能使用到引用計數。可由zval.u1.type_flag判斷
7.寫入時複製
$a = array(1,2); $b = &$a; $c = $a; //发生分离 $b[] = 3;
##事實上只有string、array兩種支援,
#8.垃圾回收
PHP變數的回收主要有兩種:主動銷毀、自動銷毀。主動銷毀指的是unset ,而自動銷毀就是PHP的自動管理機制,在return時減掉局部變數的refcount,即使沒有明確的return,PHP也會自動給加上這個操作,另外一個就是寫時複製時會斷開原來value的指向,這時候也會檢查斷開後舊value的refcount。 $a = [1];
$a[] = &$a;
unset($a);
unset($a)之前引用關係:
以上是PHP7核心剖析3之 變數的詳細內容。更多資訊請關注PHP中文網其他相關文章!