在前面大致預覽了常用變數的結構之後,我們今天來仔細的剖析一下字串的具體實現。
struct _zend_string
;
zend_refcounted_h對應的結構體:
typedef
struct _zend_refcounted_h v;
uint32_t type_info;
} u;
} zend_refcounted_h;
下面我們來了解一下具體每個成員的作用:
static zend_always_inline zend_string *
zend_string_alloc
(size_t len,
int persistent)
巨集替換後:
static zend_always_inline zend_string *
zend_string_alloc
(size_t len,
int persistent)
示例中的**xtoffsetof(zend_string, val)
表示計算出zend_string結構體的大小,而len就是要分配字串的長度,最後的+1
是留給結束字元\0
的。也就是說,分配記憶體時不僅僅分配結構體大小的記憶體,還要顧及到長度不可控的val,這樣不僅柔性的分配了記憶體,還使它與其他成員儲存在同一塊連續的空間中,在分配、釋放記憶體時可以把struct統一處理。
學習過c語言的應該知道,字串中除了最後乙個字元外不允許含有\0
,否則會被認為是字串的結束字元,這就導致了c語言的字串有很多的限制,比如不儲存、檔案等二進位制資料。但是php就沒有這樣的限制,它的字串可以儲存二進位制資料,並不會出現任何報錯,而php的這種能力就叫做字串的二進位制安全。
c語言**如下:
main()
php**:
<?php $a=
"aaa\0b"
;echo
strlen($a
);//輸出5
?>
但是php不是c語言寫的嗎?為什麼php不會報錯?我們再來回顧一下zend_string結構體,還記得成員變數len嗎?它是實現二進位制安全的關鍵,我們不需要像c一樣通過\0
來判定字串是否被讀取完成,而是通過長度len來判斷,這樣就保證了字串的二進位制安全。
在了解了zend_string結構之後,我們來了解一下用來操作zend_string的函式集合。
函式作用
zend_interned_strings_init
初始化內部字串儲存雜湊表,並把php的關鍵字等字串資訊寫進去
zend_new_interned_string
把乙個zend_string寫入cg(interned_strings)雜湊表中
zend_interned_strings_snapshot
將cg(interned_strings)雜湊表中的字串標記為永久字串,這裡標記的只有php關鍵字、內部函式名、內部方法名等
zend_interned_strings_restore
銷毀cg(interned_strings)雜湊表中型別為非永久字串的值,在php_request_shutdown階段釋放
zend_interned_strings_dtor
銷毀整個cg(interned_strings)雜湊表,在php_module_shutdown階段釋放
zend_string_hash_val
得到字串的雜湊值,沒有則實時計算
zend_string_forget_hash_val
將字串的雜湊值置為0
zend_string_refcount
讀取字串的引用計數
zend_string_addref
引用計數+1
zend_string_delref
引用計數-1
zend_string_alloc
分配記憶體及初始化字串的值
zend_string_init
初始化字串並在最後追加\0
zend_string_cop
使用引用計數方式複製字串
zend_string_dup
直接複製乙個字串
zend_string_extend
擴容到len,保留原來的值
zend_string_truncate
截斷到len,保留開頭到len的值
zend_string_free
釋放字串記憶體
zend_string_release
gc引用遞減,直到為0時釋放記憶體
zend_string_equals
普通判等
zend_string_equals_ci
基於二進位制安全,兩個zend_string型別字串判等
zend_string_equals_literal_ci
基於二進位制安全,zend_string型別和char*字串判等
zend_inline_hash_func
計算字串的雜湊值
zend_intern_known_strings
往zend_intern_known_strings全域性陣列寫入str
下面挑幾個函式來介紹一下。
zend_string_init函式主要負責把乙個普通的字串轉化為zend_string結構體。
static zend_always_inline zend_string *
zend_string_init
(const
char
*str, size_t len,
int persistent)
該函式主要用於對字串的擴容,注意這裡擴容不會改變原來儲存的值,只是把長度擴大到len。
static zend_always_inline zend_string *
zend_string_extend
(zend_string *s, size_t len,
int persistent)
else
} ret =
zend_string_alloc
(len, persistent)
;memcpy
(zstr_val
(ret)
,zstr_val
(s),
zstr_len
(s)+1)
;return ret;
}
主要基於二進位制安全對兩個字串進行判等,我們來看下php是怎麼比較兩個字串的。
#define zend_string_equals_ci(s1, s2) \
(zstr_len(s1) == zstr_len(s2) && !zend_binary_strcasecmp(zstr_val(s1), zstr_len(s1), zstr_val(s2), zstr_len(s2)))
zend_api int zend_fastcall zend_binary_strcasecmp
(const
char
*s1, size_t len1,
const
char
*s2, size_t len2)
/* len =
min(len1, len2)
;while
(len--)}
return
(int
)(len1 - len2)
;}
感興趣的同學可以到原始碼中檢視。 深入理解PHP7核心之OBJECT
今天我來講講object 物件 的一些變化。php5中,物件的定義如下 typedef struct zend object zend object 其中ce儲存了這個物件所屬的類,關於properties table和properties,properties table是申明的屬性,proper...
深入理解PHP7核心之Reference
上一章說過引用 reference 在php5的時候是乙個標誌位,而在php7以後我們把它變成了一種新的型別 is refernce.然而引用是一種很常見的應用,所以這個變化帶來了很多的變化,也給我們在做php7開發的時候,因為有的時候疏忽忘了處理這個型別,而帶來不少的bug.最簡單的情況,就是在處...
跟廠長學PHP7核心(一) 發展史
1994年,一位名叫rasmus lerdorf的兄台為了在網上展示自己的履歷和網頁流量的統計,用perl開發了一套指令碼,後來因與日俱增的需求無法得到滿足,lerdorf便使用c語言進行了重寫,重寫後的程式支援資料庫的訪問,以及web應用程式的簡單開發,備受好評,隨後便以personal home...