為 PHP 編寫 C 語言擴展能突破性能瓶頸、封裝底層庫。本文以 ext_skel 生成骨架為起點,詳細記錄 config.m4 配置、C/頭文件修改、編譯安裝、php.ini 掛載、函數參數解析(zend_parse_parameters)全流程,並提供帶參數函數實例。
./configure && make 過(生成 phpize、頭文件)。cd php-src/ext
./ext_skel --extname=hmc
# 生成 hmc/ 目錄,包含 config.m4, hmc.c, php_hmc.h, tests/ 等
# 編輯 hmc/config.m4
# 找到並取消註釋以下其中一組(推薦 PHP_ARG_ENABLE,編譯時用 --enable-hmc)
PHP_ARG_ENABLE(hmc, whether to enable hmc support,
[ --enable-hmc Enable hmc support])
# 原註釋行以 dnl 開頭,刪除 dnl 即可
#include "php_hmc.h"
// 1. 宣告函數入口表
const zend_function_entry hmc_functions[] = {
PHP_FE(confirm_hmc_compiled, NULL) // 測試用,保留或移除
PHP_FE(say_hello, NULL) // 新增:我們的函數
PHP_FE_END // 必須以此結尾
};
// 2. 模組入口結構體(通常無需修改)
zend_module_entry hmc_module_entry = {
STANDARD_MODULE_HEADER,
"hmc",
hmc_functions,
NULL, NULL, NULL, NULL, NULL,
"0.1.0",
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(hmc)
// 3. 實現 say_hello() 無參版
PHP_FUNCTION(say_hello) {
php_printf("hello world\n");
}
// 4. 實現帶參數版本(替換上方)
PHP_FUNCTION(say_hello) {
char *name;
size_t name_len;
// 解析參數:1 個字串,"s" 類型
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
return; // 錯誤已由引擎拋出
}
php_printf("hello world, %s\n", name);
}
#ifndef PHP_HMC_H
#define PHP_HMC_H
extern zend_module_entry hmc_module_entry;
#define phpext_hmc_ptr &hmc_module_entry
#define PHP_HMC_VERSION "0.1.0"
PHP_FUNCTION(confirm_hmc_compiled);
PHP_FUNCTION(say_hello); // 新增宣告
#endif
cd hmc
phpize # 生成 configure、Makefile 等
./configure --enable-hmc # 指定啟用本擴展
make
sudo make install
# 輸出:Installing shared extensions: /usr/lib/php/20210902/hmc.so
# 1. 找到 php.ini
php --ini
# 2. 在 [PHP] 區塊添加
extension=hmc.so
# 3. 重啟 PHP-FPM / Apache
sudo systemctl restart php8.1-fpm
# 4. 驗證
php -m | grep hmc # 列表中出現 hmc
php -r "say_hello();" # 輸出: hello world
php -r "say_hello('PHP');" # 輸出: hello world, PHP
| 字元 | C 類型 | PHP 類型 | 備註 |
|---|---|---|---|
| l | zend_long | int | 平台相關長度 (32/64位) |
| d | double | float | |
| s | char*, size_t | string | 二進制安全,需配合長度變量 |
| b | zend_bool | bool | 0/1 |
| a | zval* | array | 返回 HashTable* |
| o | zval* | object | |
| r | zval* | resource | |
| z | zval* | mixed | 任意類型,不分離 |
| | | 後續參數為可選 | ||
| / | 強制分離 zval (copy-on-write) | ||
| ! | 允許 null (僅用於 a, o, O, r, z) | ||
phpize: command not found → 安裝 php-dev / php-devel 包。configure: error: Cannot find php.h → 確保 PHP 源碼已 make 或安裝開發包。hmc_functions 表是否以 PHP_FE_END 結尾、頭文件是否宣告、PHP_FUNCTION 宏展開正確。zend_parse_parameters 格式字串與參數指標匹配、記憶體管理 (emalloc/efree) 配對。