17 直譯器的執行過程

2021-07-11 10:01:46 字數 2224 閱讀 4110

這裡將介紹引擎內部執行乙個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()函式執行,整個函式比較長,主要可以分為以下幾個階段:

解析命令列引數

初始化環境

編譯執行php**

清理環境並返回退出

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

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

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

phpapi int php_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,原型為:

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:

zend_api zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type 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:

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資訊的附加功能,因為引擎初始化是發生在模組請求初始化之前,而模組請求初始化又是在編譯和執行之前,所以這樣的覆蓋能達到目的。

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

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

PHP核心探索之直譯器的執行過程

cli command line inte ce 即php的命令列模式,現在此sapi是默www.cppcns.com認安裝的,我們在伺服器上安裝完php之後www.cppcns.com,一般會生成乙個可執行檔案,假設此檔案為 usr local bin php 那麼我們在shell下可以用以下命令...

C 編譯,執行過程 具體解釋。

要更深入了解c 必需要知道乙個程式從開始到結束都幹了些什麼,怎麼幹的。所以我從c 編譯到執行過程,解析下程式是怎麼跑的。首先,初略的說一下之前c 的編譯過程。c 編譯過程包含預編譯 彙編 編譯 鏈結。稱為乙個可執行檔案。windows平台下為.exe檔案 預編譯主要展開包括的標頭檔案,巨集定義等操作...