PHP解譯器發動機執行流程

來源:互聯網
上載者:User
PHP解譯器引擎執行流程

??? 這裡將介紹引擎內部執行一個PHP指令碼的流程,以cli SAPI為例子來對流程中核心的部分做簡單介紹,省去一些初始化及清理操作。
??? CLI(Command Line Interface)即PHP的命令列模式,現在此SAPI是預設安裝的,我們在伺服器上安裝完PHP之後,一般會產生一個可執行檔,假設此檔案為/usr/local/bin/php ,那麼我們在SHELL下可以用以下命令來執行一個PHP指令碼:
/usr/local/bin/php -f test.php
這個命令將執行目前的目錄下的test.php指令碼,我們暫且不關心test.php具體內容,只關心一下這個執行的內部過程是怎麼樣的。


????? CLI的主原始碼檔案在{PHPSRC}/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的指令碼,這個函數定義在{PHPSRC}/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,這個函數定義在{PHPSRC}/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是一個函數指標,其聲明在{PHPSRC}/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函數定義在{PHPSRC}/Zend/zend_language_scanner.c,通過聲明可以看到這個函數以zend_file_handle指標作為參數,返回一個指向zend_op_array的指標。


zend_execute也是一個函數指標,其聲明在{PHPSRC}/Zend/zend_execute.c:
ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);?
同樣在引擎初始化的時候,會將execute函數的地址賦值給zend_execute,execute的定義在{PHPSRC}/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(http://www.derickrethans.nl/projects.html#vld),此擴充就是在每次請求初始化的鉤子函數(PHP_RINIT_FUNCTION)中,將zend_execute和zend_compile_file替換成自己的vld_execute和vld_compile_file,這兩個函數其實是對原始函數進行了封裝,添加了輸出opcode資訊的附加功能,因為引擎初始化是發生在模組請求初始化之前,而模組請求初始化又是在編譯和執行之前,所以這樣的覆蓋能達到目的。

?

?

原文地址: http://blog.csdn.net/phpkernel/article/details/5716342

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.