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