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

PHP 5.6 撰寫擴展入門:ext_skel 產生骨架、編譯安裝與函數實作完整流程

     編輯:PHP 綜合知識

手把手教學在 PHP 5.6 環境下開發 C 語言擴展:使用 ext_skel 產生骨架、修改 config.m4、實作 PHP_FUNCTION、編譯安裝 .so、撰寫 PHP 測試腳本驗證。以字串與整數拼接函數 extstrcat 為例。

前置需求

  • PHP 5.6 原始碼套件(php-5.6.x.tar.gz)
  • 建置工具:autoconf, automake, libtool, gcc, make
  • PHP 開發頭文件:php5-dev (Debian/Ubuntu) 或 php-devel (RHEL/CentOS)

步驟 1:產生擴展骨架

# 進入 PHP 原始碼 ext/ 目錄
cd php-5.6.x/ext

# 定義函數原型檔
cat > extstrcat.def << 'EOF'
string extstrcat(string strarg, int intarg)
EOF

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

步驟 2:啟用 config.m4

# 編輯 ext/extstrcat/config.m4
# 找到並取消註解以下幾行(移除開頭 dnl)
PHP_ARG_ENABLE(extstrcat, whether to enable extstrcat support,
[  --enable-extstrcat       Enable extstrcat support])

步驟 3:實作 PHP_FUNCTION

// 編輯 ext/extstrcat/extstrcat.c
// 找到 PHP_FUNCTION(extstrcat) 並替換為:

PHP_FUNCTION(extstrcat)
{
    char *strarg = NULL;
    size_t strarg_len;
    zend_long intarg;  // PHP 5.6 使用 long
    
    // 解析參數:"s"=string, "l"=long
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &strarg, &strarg_len, &intarg) == FAILURE) {
        return;
    }

    // 整數轉字串
    char intargstr[32];
    int intarg_len = snprintf(intargstr, sizeof(intargstr), "%ld", intarg);

    // 分配結果記憶體
    size_t ret_len = strarg_len + intarg_len + 1;
    char *retstr = emalloc(ret_len); // 使用 PHP 記憶體管理
    
    // 拼接
    memcpy(retstr, strarg, strarg_len);
    memcpy(retstr + strarg_len, intargstr, intarg_len);
    retstr[ret_len - 1] = '\0';

    // 回傳字串(1 表示複製,0 表示移交所有權)
    RETVAL_STRINGL(retstr, ret_len - 1, 1);
    efree(retstr); // 複製後釋放臨時緩衝區
}

關鍵 API 說明

宏/函數用途
zend_parse_parameters()解析 PHP 傳入參數,型別規格:"s"=string, "l"=long, "d"=double, "b"=bool, "a"=array, "o"=object, "z"=zval
TSRMLS_CC線程安全宏(PHP 5.6 必須),PHP 7+ 已移除
emalloc()/efree()PHP 記憶體管理,請求結束自動清理
RETVAL_STRINGL()回傳二進位安全字串(長度、是否複製)
RETURN_STRING()回傳字串並直接 return

步驟 4:編譯安裝

cd php-5.6.x/ext/extstrcat
phpize
./configure --enable-extstrcat
make

# 複製 .so 到 PHP 擴展目錄
cp modules/extstrcat.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/

# 修改 php.ini
echo "extension=extstrcat.so" >> /usr/local/etc/php.ini

# 重啟 PHP-FPM / Apache
systemctl restart php-fpm

步驟 5:驗證測試

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

$result = extstrcat('testarg', 1234);
var_dump($result); // string(11) "testarg1234"

// 命令列執行
// php test_extstrcat.php
?>

常見問題排查

  • phpize 失敗:確認安裝 php5-dev/php-devel 且版本匹配。
  • configure 錯誤:檢查 config.m4 語法、PHP_ARG_ENABLE 參數。
  • 編譯錯誤:C 語法錯誤、缺少頭文件、TSRMLS_CC 遺漏(PHP 5.6 必須)。
  • 載入失敗:php -m 檢查模組、php -i | grep extension_dir 確認路徑、ldd extstrcat.so 檢查相依庫。
  • 函數未定義:確認 PHP_FE(extstrcat) 在 zend_function_entry 陣列中(ext_skel 自動產生)。

PHP 7+ 差異提醒

項目PHP 5.6PHP 7+
整數型別long / zend_longzend_long
TSRMLS必須 TSRMLS_CC移除,不需傳遞
zval 操作巨集操作新 API (ZVAL_*)
記憶體管理emalloc/efree相同,但引入 zend_string

學習資源

  • 官方文件:PHP Internals Book
  • 原始碼參考:ext/standard/string.c 內建字串函數實作
  • 進階主題:物件導向擴展、INI 設定、資源類型、非同步 I/O

完成第一個擴展後,你將擁有深入 PHP 核心、突破效能瓶頸、封裝 C/C++ 庫的能力。

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