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

PHP 生命週期深度解析:從 SAPI 啟動到請求終結

     編輯:PHP 綜合知識

PHP 在 Web 伺服器環境中並非獨立執行,而是由 SAPI(Server API)層載入並管理。理解 PHP 的四階段生命週期(MINIT/MSHUTDOWN、RINIT/RSHUTDOWN),是編寫高效能擴展與排查記憶體洩漏的基礎。

整體流程圖

SAPI 啟動
   │
   ├─► MINIT (模組初始化) —— 所有擴展 MINIT 執行一次
   │
   ├─► 請求循環 (每個 HTTP 請求)
   │      │
   │      ├─► RINIT (請求初始化) —— 每請求執行
   │      │
   │      ├─► 執行 PHP 腳本
   │      │
   │      └─► RSHUTDOWN (請求關閉) —— 每請求執行
   │
   └─► MSHUTDOWN (模組關閉) —— SAPI 關閉時執行一次

兩對啟動/關閉階段詳解

階段時機用途持久性
MINITSAPI 啟動後、首個請求前註冊常數、類別、資源類型、INI 設定、流包裝器、過濾器跨請求持久(整個 SAPI 生命週期)
MSHUTDOWNSAPI 關閉前釋放持久資源、關閉連線池、清理全域狀態—
RINIT每個請求開始初始化請求級變數($_GET、$_POST、$_SESSION)、建立資料庫連線單請求
RSHUTDOWN每個請求結束釋放請求級資源、關閉非持久連線、清理 Session 寫入—

MINIT 典型實作範例

PHP_MINIT_FUNCTION(myextension) {
    // 1. 執行緒安全全域變數分配 (ZTS 環境)
    #ifdef ZTS
    ts_allocate_id(&myextension_globals_id, sizeof(php_myextension_globals),
                   (ts_allocate_ctor) myextension_globals_ctor,
                   (ts_allocate_dtor) myextension_globals_dtor);
    #else
    myextension_globals_ctor(&myextension_globals TSRMLS_CC);
    #endif

    // 2. 註冊 INI 設定
    REGISTER_INI_ENTRIES();

    // 3. 註冊常數
    REGISTER_LONG_CONSTANT("MYEXT_MEANING", 42, CONST_CS | CONST_PERSISTENT);
    REGISTER_STRING_CONSTANT("MYEXT_FOO", "bar", CONST_CS | CONST_PERSISTENT);

    // 4. 註冊資源類型 (持久/非持久)
    le_myresource = zend_register_list_destructors_ex(
        php_myext_myresource_dtor, NULL, "My Resource Type", module_number);
    le_myresource_persist = zend_register_list_destructors_ex(
        NULL, php_myext_myresource_dtor, "My Resource Type", module_number);

    // 5. 註冊流過濾器
    if (FAILURE == php_stream_filter_register_factory("myfilter", &php_myextension_filter_factory TSRMLS_CC))
        return FAILURE;

    // 6. 註冊流包裝器
    if (FAILURE == php_register_url_stream_wrapper("myproto", &php_myextension_stream_wrapper TSRMLS_CC))
        return FAILURE;

    // 7. 註冊自動全域變數
    #ifdef ZEND_ENGINE_2
    if (zend_register_auto_global("_MYEXTENSION", sizeof("_MYEXTENSION")-1, NULL TSRMLS_CC) == FAILURE)
        return FAILURE;
    zend_auto_global_disable_jit("_MYEXTENSION", sizeof("_MYEXTENSION")-1 TSRMLS_CC);
    #else
    if (zend_register_auto_global("_MYEXTENSION", sizeof("_MYEXTENSION")-1 TSRMLS_CC) == FAILURE)
        return FAILURE;
    #endif

    return SUCCESS;
}

CLI 模式下的生命週期

CLI 可視為「單請求迷你 SAPI」:

  1. 啟動 CLI SAPI → 執行 MINIT。
  2. 執行腳本 → RINIT → 執行程式碼 → RSHUTDOWN。
  3. 結束 → MSHUTDOWN → 退出行程程序。

關鍵啟示

  • 持久資源(資料庫連線池、快取句柄)應在 MINIT 建立,MSHUTDOWN 釋放。
  • 請求資源(單次查詢結果、暫存檔)應在 RINIT 建立,RSHUTDOWN 釋放。
  • 錯誤處理(die()、exit()、E_ERROR)會觸發 longjmp() 直接跳至請求結束,**略過後續程式碼**(含 free()),導致記憶體洩漏 —— 這正是 ZendMM 存在的意義。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved