PHP核心分析之深入理解字串(七)

2021-10-01 16:23:05 字數 3649 閱讀 6580

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);

}

感興趣的同學可以到原始碼中檢視。

深入理解字串

1 字串處理 5 n 9 string str helloworld str str.substring 5,10 即可求出world object equals 比較記憶體位址 string equals 比較內容 1.暫存器 2.棧3.堆 4.靜態儲存區 5.常量儲存區 宣告final stat...

深入理解字串指標和字串陣列

首先我們來看一段程式 include int main 它的輸出結果如圖 分析 我們首先宣告了乙個字串陣列和乙個字串指標。然後將他們等同型別的輸出做對比。從輸出結果我們可以看到,想要輸出整個字串。分別以 s格式輸出str和ps即可。1.字串指標名ps和陣列名str都存放著字串的首位址。而字串本身存放...

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

在前面大致預覽了常用變數的結構之後,我們今天來仔細的剖析一下字串的具體實現。struct zend string zend refcounted h對應的結構體 typedef struct zend refcounted h v uint32 t type info u zend refcount...