在 PHP 內核中,最基礎也最關鍵的數據結構莫過於 zval(在源碼中定義為 _zval_struct)。它是 PHP 所有變量類型在 C 層的統一表示,理解它是編寫高性能擴展的前提。
typedef union _zvalue_value {
long lval; /* 長整型值 */
double dval; /* 雙精度浮點型值 */
struct {
char *val;
int len;
} str; /* 字符串值 */
HashTable *ht; /* 哈希表值(PHP 數組) */
zend_object_value obj; /* 對象值 */
} zvalue_value;
struct _zval_struct {
zvalue_value value; /* 實際存儲的值 */
zend_uint refcount; /* 引用計數 */
zend_uchar type; /* 當前活躍類型 */
zend_uchar is_ref; /* 是否為引用 */
};
可以看到,_zval_struct 的第一個字段是一個聯合體 zvalue_value,它能夠存儲長整型、雙精度浮點型、字符串、哈希表(即 PHP 數組)以及對象等所有 PHP 支持的數據類型。第二個字段 refcount 用於引用計數,實現写時複製(Copy-on-Write)機制;第三個字段 type 標識當前實際存儲的數據類型;第四個字段 is_ref 則標記該變量是否為引用類型。
換句話說,PHP 中的每一個變量——無論是整數、浮點數、字符串、數組還是對象——在 C 層面上都是一個 _zval_struct 結構體實例。
進入 PHP 源碼目錄下的 ext 文件夾,執行以下命令生成名為 my_module 的擴展骨架:
./ext_skel --extname=my_module
執行完成後,會在當前目錄下生成一個 my_module 文件夾,包含擴展開發所需的基礎文件結構。
在生成的 my_module.h 文件中聲明你的 PHP 函數:
PHP_FUNCTION(my_function);
在 my_module.c 文件的 my_module_functions 數組中註冊該函數(注意數組名以模塊名稱開頭):
PHP_FE(my_function, NULL)
接下來在 my_module.c 中實現 PHP_FUNCTION(my_function)。核心步驟是參數解析——將傳入的 PHP 類型轉換為 C 類型,這需要使用 zend_parse_parameters 函數:
int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...);
| 類型標識符 | PHP 類型 | C 存儲方式 |
|---|---|---|
| l | long (整數) | long |
| d | double (浮點數) | double |
| s | string (字符串,可含空字節) | char * 及長度 |
| b | boolean (布爾值) | zend_bool |
| r | resource (資源) | zval * |
| a | array (數組) | zval * |
| o | object (任意類對象) | zval * |
| O | object (指定類對象) | zval * |
| z | zval (原始 zval 指針) | zval * |
掌握這些核心概念與流程,你就可以開始編寫屬於自己的高性能 PHP C 擴展了。