首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 呼叫 C/C++ 共享庫(.so/.dll)完整擴充開發指南

     編輯:PHP 綜合知識

架構概覽

PHP 擴充開發流程:C 原始碼 → 編譯為共享庫 .so → 撰寫 PHP 擴充封裝層 → 編譯為 PHP 模組 .so → PHP 載入呼叫。

第一階段:建立 C 共享庫

1.1 撰寫核心邏輯 mylib.c

#include "mylib.h"
#include 

char* 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;
}

1.2 標頭檔 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

1.3 編譯共享庫

# 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

第二階段:建立 PHP 擴充骨架

2.1 定義 PHP 公開函數 myfunctions.def

string hello(int a)
int hello_add(int a, int b)

2.2 產生骨架

cd php-src/ext
./ext_skel --extname=myfunctions --proto=myfunctions.def

2.3 修改 config.m4 啟用擴充

PHP_ARG_ENABLE(myfunctions, whether to enable myfunctions support,
[  --enable-myfunctions   Include myfunctions support])

第三階段:實作 PHP ↔ C 橋接層

3.1 編輯 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);
}

3.2 修改 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));"

進階主題

  • 記憶體管理:C 庫回傳的記憶體需由誰釋放?建議 C 庫使用靜態緩衝區或 PHP 端 estrdup 複製後 efree
  • 錯誤傳遞:C 端回傳錯誤碼,PHP 端拋出 Exception
  • 複雜資料結構:陣列/物件轉換需手寫 zval 操作,考慮使用 php_serialize/json 交換
  • 執行緒安全:ZTS 環境下需使用 TSRMLS 巨集

替代方案比較

方案優點缺點適用場景
PHP 擴充 (本文)效能最佳、型別安全、原生整合開發門檻高、需編譯部署高頻運算、核心邏輯保護
FFI (PHP 7.4+)純 PHP 撰寫、無需編譯、動態載入效能較低、C 型別映射複雜快速原型、偶爾呼叫系統庫
shell_exec / proc_open最簡單、語言無關進程開銷大、安全風險、資料交換麻煩低頻、長時間運行的外部程式
gRPC / HTTP 微服務跨語言、獨立部署、可擴展網路延遲、架構複雜度高大型系統、多語言團隊
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved