跟廠長學PHP7核心(八) 深入理解字串的實現

2021-08-28 08:10:25 字數 4014 閱讀 6021

在前面大致預覽了常用變數的結構之後,我們今天來仔細的剖析一下字串的具體實現。

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...