PHP 作為 Apache 模塊運行時,請求處理的入口是 php_handler()。本文通過核心 C 源碼片段,梳理從 Apache 接收請求到 Zend 引擎執行腳本的完整鏈路。
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() 啟動編譯執行流程。
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() 執行。
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");
}
php_handler 封裝請求為 zend_file_handle。zend_compile_file 生成 op_array(AST → opcode)。execute() 初始化 execute_data(虛擬機棧幀),進入 while(1) 循環,逐條分發 opcode handler 執行。execute_data 實現,EG(current_execute_data) 始終指向當前幀。理解這一流程,是深入 PHP 擴展開發、性能分析(如 xhprof、vld)與 Opcode 緩存(OPcache)原理的基石。