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

PHP 5.6 編寫擴展入門:ext_skel 生成骨架、字串整數連接函數實作與編譯安裝全流程

     編輯:PHP 相關知識

當 PHP 內建函數無法滿足效能或功能需求時,編寫 C 語言擴展是終極解決方案。本文以 PHP 5.6 為例,完整記錄從 ext_skel 生成骨架、定義函數原型、修改 config.m4、實作 PHP_FUNCTION、phpize 編譯、安裝 .so、修改 php.ini、測試驗證的全流程,實作一個字串與整數連接的簡單擴展函數 extstrcat()。

前置準備

# 1. 取得 PHP 原始碼 (含 ext 目錄)
wget https://php.net/distributions/php-5.6.40.tar.gz
tar -xzf php-5.6.40.tar.gz
cd php-5.6.40/ext

步驟 1: 定義函數原型 (extstrcat.def)

# 檔案: ext/extstrcat.def
string extstrcat(string strarg, int intarg)

步驟 2: 生成擴展骨架

./ext_skel --extname=extstrcat --proto=extstrcat.def
# 產生 ext/extstrcat/ 目錄,包含 config.m4, extstrcat.c, php_extstrcat.h 等

步驟 3: 修改 config.m4 啟用擴展

編輯 ext/extstrcat/config.m4,移除以下行前的 dnl 註解:

PHP_ARG_ENABLE(extstrcat, whether to enable extstrcat support,
[  --enable-extstrcat       Enable extstrcat support])

步驟 4: 實作 PHP_FUNCTION (extstrcat.c)

PHP_FUNCTION(extstrcat)
{
    char *strarg = NULL;
    int argc = ZEND_NUM_ARGS();
    int strarg_len;
    long intarg;

    char intargstr[10];
    int retstrlen = 0;
    char *retstr = NULL;

    // 解析參數: "s"=string, "l"=long (整數)
    if (zend_parse_parameters(argc TSRMLS_CC, "sl", &strarg, &strarg_len, &intarg) == FAILURE) {
        return;
    }

    // 整數轉字串
    snprintf(intargstr, 9, "%d", intarg);

    // 計算結果長度並分配記憶體
    retstrlen = strarg_len + strlen(intargstr) + 1;  // +1 for null terminator
    retstr = (char *)malloc(sizeof(char) * retstrlen);
    memset(retstr, '\0', retstrlen);

    // 連接字串
    strncat(retstr, strarg, strlen(strarg));
    strncat(retstr, intargstr, strlen(intargstr));

    // 回傳字串 (第二參數 1 表示需複製字串)
    RETURN_STRING(retstr, 1);

    // 釋放臨時記憶體 (RETURN_STRING 複製後需自行 free)
    free(retstr);
}

關鍵 Zend API 解析

宏/函數用途
ZEND_NUM_ARGS()取得實際傳入參數個數
zend_parse_parameters()解析參數: "s"=字串, "l"=長整數, "d"=雙精度, "b"=布林, "a"=陣列, "o"=物件, "r"=資源
TSRMLS_CC線程安全巨集 (PHP 5.6 必需,PHP 7 已移除)
RETURN_STRING(str, duplicate)回傳字串: duplicate=1 複製字串, 0 直接使用 (需確保生命週期)
RETURN_LONG(), RETURN_DOUBLE(), RETURN_BOOL()回傳其他型別
php_error()發出錯誤/警告/通知

步驟 5: 編譯安裝

cd ext/extstrcat

# 1. 生成 configure 腳本
phpize

# 2. 配置 (啟用擴展)
./configure --enable-extstrcat

# 3. 編譯
make

# 成功後在 modules/ 產生 extstrcat.so

步驟 6: 安裝到 PHP 擴展目錄

# 查詢擴展目錄
php -i | grep extension_dir
# 輸出範例: /usr/local/lib/php/extensions/no-debug-non-zts-20131226/

# 複製 .so 檔案
cp modules/extstrcat.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/

步驟 7: 修改 php.ini 載入擴展

extension = extstrcat.so

重啟 PHP-FPM / Apache 生效。

步驟 8: 測試驗證

<?php
// test_extstrcat.php
if (!extension_loaded('extstrcat')) {
    dl('extstrcat.' . PHP_SHLIB_SUFFIX);  // CLI 可動態載入
}

$ret = extstrcat('testarg', 1234);
echo $ret;  // 輸出: testarg1234
?>
$ php test_extstrcat.php
testarg1234

驗證擴展載入

$ php -m | grep extstrcat
extstrcat

$ php -i | grep extstrcat
extstrcat support => enabled

常見問題與解決

問題原因解決
configure 找不到 phpize未安裝 php-dev / php-devel 套件apt-get install php5-dev / yum install php-devel
編譯錯誤: TSRMLS_CC 未定義PHP 7+ 已移除 TSRMLSPHP 5.6 保留,確認 phpize 版本正確
RETURN_STRING 第二參數警告PHP 7 移除 duplicate 參數PHP 5.6 需保留 1
dl() 無法載入php.ini disable_functions 含 dl移除 dl 限制或直接修改 php.ini 載入
中文亂碼字串編碼不一致確保原始碼 UTF-8,Zend 引擎內部 UTF-8

總結

PHP 擴展開發標準流程:定義原型 → ext_skel 生成骨架 → 修改 config.m4 → 實作 PHP_FUNCTION → phpize → configure → make → 安裝 .so → 修改 php.ini → 測試。核心技術點:zend_parse_parameters 參數解析、RETURN_STRING 回傳值處理、記憶體管理 (malloc/free)、TSRMLS_CC 線程安全。掌握此流程即可將效能關鍵路徑下沉至 C 層,突破 PHP 使用者空間限制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved