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

PHP 模組開發學習心得:從 dl() 追蹤擴展載入流程

     編輯:PHP 綜合知識

深入 PHP 核心原始碼,從 dl() 函式追蹤動態擴展(.so)的載入、註冊、初始化完整流程,釐清 ZEND 模組機制關鍵節點。

PHP 核心架構分層

PHP 核心架構分層圖

  • TSRM:Thread Safe Resource Manager,執行緒安全管理層。
  • SAPI:Server API,對外服務介面(CLI、FastCGI、Apache 模組等)。
  • PHP Core + Zend Engine:請求管理、編譯執行、記憶體分配核心。
  • Extension Layer:擴展層,所有對外功能(標準庫、資料庫驅動等)皆以擴展形式提供。

擴展載入兩種方式

  1. 靜態編譯:./configure --enable-extname 重新編譯 PHP 二進制。
  2. 動態載入:編譯為 .so,透過 php.ini 的 extension=extname.so 或程式碼 dl('extname.so') 載入。

dl() 函式原始碼追蹤

原始碼位置:PHP_SRC_HOME/ext/standard/dl.c

1. PHP_FUNCTION(dl)

PHPAPI PHP_FUNCTION(dl) {
    // ... 參數解析 ...
    php_dl(filename, MODULE_TEMPORARY, return_value, 0 TSRMLS_CC);
    // ...
}

2. php_dl()

PHPAPI void php_dl(char *file, int type, zval *return_value, int start_now TSRMLS_DC) {
    if (php_load_extension(file, type, start_now TSRMLS_CC) == FAILURE) {
        // 錯誤處理
    }
}

3. php_load_extension() —— 核心流程

PHPAPI int php_load_extension(char *filename, int type, int start_now TSRMLS_DC) {
    // 1. 解析檔案路徑
    // 2. 載入動態連結庫
    handle = DL_LOAD(libpath);
    
    // 3. 取得模組入口函式 get_module()
    get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module");
    
    // 4. 呼叫 get_module() 取得 zend_module_entry 結構
    module_entry = get_module();
    
    // 5. 註冊模組到 Zend 引擎
    if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) {
        // 錯誤處理
    }
    
    // 6. 模組啟動 (MINIT)
    if ((type == MODULE_TEMPORARY || start_now) 
        && zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) {
        // 錯誤處理
    }
    
    // 7. 請求啟動 (RINIT)
    if ((type == MODULE_TEMPORARY || start_now) 
        && module_entry->request_startup_func) {
        // 錯誤處理
    }
    
    return SUCCESS;
}

關鍵節點總結

階段函式/宏說明
載入 .soDL_LOAD()系統動態連結器載入共享庫
取得入口DL_FETCH_SYMBOL("get_module")每個擴展必須導出的 C 函式
模組註冊zend_register_module_ex()將 zend_module_entry 註冊到模組表
模組啟動zend_startup_module_ex() → PHP_MINIT_FUNCTION常數註冊、資源類型註冊、INI 設定等
請求啟動request_startup_func → PHP_RINIT_FUNCTION每請求初始化(如 Session、資料庫連線)

開發啟示

  • 編寫擴展時,get_module() 必須正確導出 zend_module_entry。
  • PHP_MINIT_FUNCTION 僅在模組首次載入執行一次(跨請求持久)。
  • PHP_RINIT_FUNCTION 每個 HTTP 請求皆執行一次。
  • 動態載入(dl())的擴展屬 MODULE_TEMPORARY,請求結束會自動卸載(呼叫 MSHUTDOWN/RSHUTDOWN)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved