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

PHP 內核探秘:請求處理流程核心代碼深度解讀

     編輯:PHP 相關知識

PHP 內核兩大流程之一:請求處理核心代碼解讀

PHP 作為 Apache 模塊運行時,請求處理的入口是 php_handler()。本文通過核心 C 源碼片段,梳理從 Apache 接收請求到 Zend 引擎執行腳本的完整鏈路。

1. SAPI 入口:php_handler()

static int php_handler(request_rec *r) {
    php_struct * volatile ctx;
    // ... 初始化上下文 ...
    zend_file_handle zfd;
    zfd.type = ZEND_HANDLE_FILENAME;
    zfd.filename = (char *) r->filename;  // 當前請求的腳本文件
    zfd.free_filename = 0;
    zfd.opened_path = NULL;
    // 編譯並執行腳本
    zend_execute_scripts(ZEND_INCLUDE TSRMLS_CC, NULL, 1, &zfd);
    // ... 清理工作 ...
}

關鍵點:將 Apache 的 request_rec 轉為 Zend 的 zend_file_handle,調用 zend_execute_scripts() 啟動編譯執行流程。

2. 編譯入口:zend_execute_scripts()

ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...) {
    // ...
    EG(active_op_array) = zend_compile_file(file_handle, type TSRMLS_CC);  // 詞法/語法分析 → 生成 opcode 數組
    // ...
    zend_execute(EG(active_op_array) TSRMLS_CC);  // 執行 opcode
    // ...
}

zend_compile_file() 負責將 PHP 源碼編譯為 zend_op_array(opcode 序列),隨後交由 zend_execute() 執行。

3. 執行核心:execute() / zend_execute()

ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) {
    zend_execute_data execute_data;  // 執行上下文(棧幀)
    // 初始化執行上下文:符號表、錯誤報告、臨時變量、CV 變量等
    EX(Ts) = ...;  // 臨時變量存儲
    EX(CVs) = ...; // 編譯期變量(靜態分析可知的變量)
    EX(op_array) = op_array;
    // 壓棧:保存舊執行上下文,切換到新上下文
    EX(prev_execute_data) = EG(current_execute_data);
    EG(current_execute_data) = &execute_data;
    EG(in_execution) = 1;
    // 設置起始 opcode
    if (op_array->start_op) ZEND_VM_SET_OPCODE(op_array->start_op);
    else ZEND_VM_SET_OPCODE(op_array->opcodes);
    // $this 指針處理
    if (op_array->uses_this && EG(This)) { /* refcount++ 並加入符號表 */ }
    EG(opline_ptr) = &EX(opline);  // 實時追蹤當前 opcode
    // 主執行循環
    while (1) {
        #ifdef ZEND_WIN32
        if (EG(timed_out)) { zend_timeout(0); }
        #endif
        // 調用當前 opcode 對應的 handler,返回 >0 表示返回/退出
        if (EX(opline)->handler(&execute_data TSRMLS_CC) > 0) {
            return;
        }
    }
    zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
}

核心流程總結

  1. SAPI 層:php_handler 封裝請求為 zend_file_handle。
  2. 編譯階段:zend_compile_file 生成 op_array(AST → opcode)。
  3. 執行階段:execute() 初始化 execute_data(虛擬機棧幀),進入 while(1) 循環,逐條分發 opcode handler 執行。
  4. 上下文切換:函數調用/返回通過壓棧/彈棧 execute_data 實現,EG(current_execute_data) 始終指向當前幀。

理解這一流程,是深入 PHP 擴展開發、性能分析(如 xhprof、vld)與 Opcode 緩存(OPcache)原理的基石。

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