PHP直譯器引擎執行流程

2021-06-21 17:13:19 字數 2500 閱讀 2406

這裡將介紹引擎內部執行乙個php指令碼的流程,以cli sapi為例子來對流程中核心的部分做簡單介紹,省去一些初始化及清理操作。

cli(command line inte***ce)即php的命令列模式,現在此sapi是預設安裝的,我們在伺服器上安裝完php之後,一般會生成乙個可執行檔案,假設此檔案為/usr/local/bin/php ,那麼我們在shell下可以用以下命令來執行乙個php指令碼:

/usr/local/bin/php -f test.php

這個命令將執行當前目錄下的test.php指令碼,我們暫且不關心test.php具體內容,只關心一下這個執行的內部過程是怎麼樣的。

cli的主源**檔案在/sapi/cli/php_cli.c,整個過程就從這個檔案中的 main()函式執行,整個函式比較長,主要可以分為以下幾個階段:

1:解析命令列引數

2:初始化環境

3:編譯執行php**

4:清理環境並返回退出

在第1個階段中,解析-f引數為執行乙個php檔案,-f後面的test.php就是需要被執行的檔案

這裡我們將關注第3個階段,如何執行test.php中的php**。

最終是通過php_execute_script(&file_handle tsrmls_cc)來執行php的指令碼,這個函式定義在/main/main.c,原型為

[cpp]view plain

copy

phpapi 

intphp_execute_script(zend_file_handle *primary_file tsrmls_dc)  

file_handle的型別為zend_file_handle,這個是zend對檔案控制代碼的乙個封裝,裡面的內容就是和test.php相關的了。

php_execute_script最終是呼叫的zend_execute_scripts,這個函式定義在/zend/zend.c,原型為:

[css]view plain

copy

zend_api int zend_execute_scripts(int type tsrmls_dc, zval **retval, int file_count, ...)  

此函式具有可變引數,可以一次執行多個php檔案,在此函式中最核心的是呼叫zend_compile_file和zend_execute,zend_compile_file是乙個函式指標,其宣告在/zend/zend_compile.c:

[cpp]view plain

copy

zend_api zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, 

inttype tsrmls_dc);  

在引擎初始化的時候,會將compile_file函式的位址賦值給zend_compile_file,compile_file函式定義在/zend/zend_language_scanner.c,通過宣告可以看到這個函式以zend_file_handle指標作為引數,返回乙個指向zend_op_array的指標。

zend_execute也是乙個函式指標,其宣告在/zend/zend_execute.c:

[cpp]view plain

copy

zend_api 

extern

void

(*zend_execute)(zend_op_array *op_array tsrmls_dc);  

同樣在引擎初始化的時候,會將execute函式的位址賦值給zend_execute,execute的定義在/zend/zend_vm_execute.h。

通過宣告知道zend_execute以乙個指向zend_op_array結構的指標作為引數,這個指標即前面zend_compile_file的返回值,zend_execute就開始執行op_array中的op code,在執行op code的過程中,就實現了php語言的各種功能。

到這裡主要的執行工作基本就完成。

ps:為什麼要把zend_execute和zend_compile_file定義為函式指標?

在引擎初始化(zend_startup)的時候,將zend_execute指向了預設的execute,zend_compile_file指向了預設的compile_file。我們可以在實際編譯和執行之前將zend_execute和zend_compile_file重寫為其他的編譯和執行函式,這樣就為我們擴充套件引擎留下了鉤子,比如乙個比較有名的檢視php的op code的擴充套件vld(此擴充套件就是在每次請求初始化的鉤子函式(php_rinit_function)中,將zend_execute和zend_compile_file替換成自己的vld_execute和vld_compile_file,這兩個函式其實是對原始函式進行了封裝,新增了輸出opcode資訊的附加功能,因為引擎初始化是發生在模組請求初始化之前,而模組請求初始化又是在編譯和執行之前,所以這樣的覆蓋能達到目的。

**:

python直譯器執行的流程

1.詞法分析 讀取 文件 互動模式 檔案模式 字串模式三種模式採取不同的讀取策略 將其轉化為乙個個token 如 a 2 3 34 會將這個表示式轉換為a 2 3 34這幾個token,而且每乙個token都會儲存它的型別,比如a是乙個變數,34是乙個整數。在這一步語法分析中會用到grammar檔案...

php語法直譯器 php直譯器的安裝方法

php在windows下安裝配置第一步 還有2個檔案 乙個 php.ini development 乙個是 php.ini production 從名字也可以看出是開發環境跟生產環境的區別了 找到 extension dir ext 刪除最前面的分號 找到 extension php mbstrin...

php核心探索筆記 直譯器的執行過程

以cli sapi為例來對php執行核心部分進行解析。cli是php命令列模式,此sapi是預設安裝的,在伺服器端安裝過php後,生成以乙個可執行檔案,可以在shell中呼叫php命令來執行。php f xx.php執行流程 在第3個階段中,如何執行php指令碼的 通過呼叫php execute s...