這裡將介紹引擎內部執行乙個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...