PHP 擴充開發流程:C 原始碼 → 編譯為共享庫 .so → 撰寫 PHP 擴充封裝層 → 編譯為 PHP 模組 .so → PHP 載入呼叫。
mylib.c#include "mylib.h" #includechar* hello(int a) { static char buf[64]; snprintf(buf, sizeof(buf), "Hello from C, param=%d", a); return buf; } int hello_add(int a, int b) { return a + b; }
mylib.h#ifndef MYLIB_H
#define MYLIB_H
#ifdef __cplusplus
extern "C" {
#endif
char* hello(int a);
int hello_add(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
# Linux/macOS gcc -shared -fPIC -O2 -o libmylib.so mylib.c # Windows (MinGW) gcc -shared -O2 -o mylib.dll mylib.c # 安裝至系統庫路徑 sudo cp libmylib.so /usr/local/lib/ echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/local.conf sudo ldconfig
myfunctions.defstring hello(int a) int hello_add(int a, int b)
cd php-src/ext ./ext_skel --extname=myfunctions --proto=myfunctions.def
config.m4 啟用擴充PHP_ARG_ENABLE(myfunctions, whether to enable myfunctions support, [ --enable-myfunctions Include myfunctions support])
myfunctions.c#include "php_myfunctions.h"
#include "mylib.h" // 引入我們的 C 庫標頭
// 函數聲明宏
PHP_FUNCTION(hello);
PHP_FUNCTION(hello_add);
// 函數表
zend_function_entry myfunctions_functions[] = {
PHP_FE(hello, NULL)
PHP_FE(hello_add, NULL)
PHP_FE_END
};
// 模組入口
zend_module_entry myfunctions_module_entry = {
STANDARD_MODULE_HEADER,
"myfunctions",
myfunctions_functions,
NULL, NULL, NULL, NULL, NULL,
"1.0",
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(myfunctions)
// 實作 hello
PHP_FUNCTION(hello) {
zend_long a;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &a) == FAILURE) return;
char* result = hello((int)a); // 呼叫 C 庫
RETVAL_STRING(result);
}
// 實作 hello_add
PHP_FUNCTION(hello_add) {
zend_long a, b;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &a, &b) == FAILURE) return;
int sum = hello_add((int)a, (int)b);
RETVAL_LONG(sum);
}
Makefile 鏈接共享庫# 在 PHP 編譯目錄下的 Makefile 中找到 EXTRA_LIBS 或新增 EXTRA_LIBS = -lmylib # 或在 config.m4 加入 PHP_ADD_LIBRARY_WITH_PATH(mylib, /usr/local/lib, MYFUNCTIONS_SHARED_LIBADD) PHP_SUBST(MYFUNCTIONS_SHARED_LIBADD)
# 在 php-src 根目錄 ./buildconf --force ./configure --enable-myfunctions [其他參數...] make clean && make -j$(nproc) sudo make install # 重啟 PHP-FPM/Apache sudo systemctl restart php-fpm # 驗證 php -m | grep myfunctions php -r "var_dump(hello(42), hello_add(10, 20));"
estrdup 複製後 efreeExceptionzval 操作,考慮使用 php_serialize/json 交換TSRMLS 巨集| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| PHP 擴充 (本文) | 效能最佳、型別安全、原生整合 | 開發門檻高、需編譯部署 | 高頻運算、核心邏輯保護 |
| FFI (PHP 7.4+) | 純 PHP 撰寫、無需編譯、動態載入 | 效能較低、C 型別映射複雜 | 快速原型、偶爾呼叫系統庫 |
| shell_exec / proc_open | 最簡單、語言無關 | 進程開銷大、安全風險、資料交換麻煩 | 低頻、長時間運行的外部程式 |
| gRPC / HTTP 微服務 | 跨語言、獨立部署、可擴展 | 網路延遲、架構複雜度高 | 大型系統、多語言團隊 |