Zend opcode是如何被執行的?是要編譯為機器碼再執行嗎?

php先被Zend引擎編譯為opcode,那麼opcode又是如何被zend_execute執行的呢?最終是被編譯為機器碼了嗎?具體過程是如何的?


既然題主提到了Zend那麼這個問題是特指Zend Engine所實現的PHP,而不指任何其它實現(例如HHVM、Hippy、Quercus或JPHP)。

到PHP 7.0為止,Zend Engine的正式發行的版本從來都是通過解釋器實現(*)。Zend的位元組碼指令一條條進入解釋器,一條條位元組碼指令被其opcode對應的C語言寫的函數所執行。就這麼簡單。

簡易工作流程:

[ PHP源碼 ]

=&> 詞法分析 / 語法分析 -&> [ 抽象語法樹(AST) ]

=&> 位元組碼編譯器 -&> [ Zend位元組碼(指令集為 Zend opcodes) ]

=&> 位元組碼解釋器 -&> [ 程序運行結果 ]

具體解釋器是如何從opcode分派到其對應的函數,Zend Engine可以配置使用幾種不同的方式:call threading、switch threading、computed goto threading。這些名字分別是什麼意思,請參考這篇文章:Threaded Code

以最簡單的switch-threading舉例,這種解釋器的基本形式就是這樣的:

while (TRUE) {
int opcode = *program_counter;
switch (opcode) {
case ZEND_ADD:
// execute add ...
program_counter++; // next opcode
break;
case ZEND_SUB:
// execute sub ...
program_counter++; // next opcode
break;
// ...
}
}

這個解釋器自身是用C實現的,就跟一般的C程序一樣會被編譯為機器碼來執行;

但用戶輸入的PHP程序則不會被編譯為機器碼,而是編譯到包含Zend opcode的Zend位元組碼之後由這個解釋器一條條位元組碼指令解釋執行。

題主可以參考一些PHP源碼里的文檔:

  • README.ZEND_VM &<- 這是PHP-7.0.4的版本,裡面的內容對Zend Engine II和PHP 7對應的Zend Engine III都有效。

  • zend_vm_def.h &<- 同版本的PHP解釋器的主體。

  • PHPNG a New Core for PHP7 &<- PHP 7的Zend Engine III比起之前的Zend Engine II改進的一些介紹。

(*) 雖然在PHP 5.5時代,有大大嘗試給PHP加上JIT編譯,但效果不好所以放棄了。當然,效果不好主要是因為當時的Zend Engine II的底子太差,即使加上JIT也掩蓋不了運行時開銷大的問題。新的Zend Engine III的基礎好了許多,或許有希望…


PHP源碼 ==(interpreter)==&> opcode(PHP: Zend Engine 2 Opcodes,理解成彙編) ==(zend engine)==&> 機器碼


計算機只能執行機器碼,但是並不是把PHP代碼直接轉為機器碼執行,而是轉化為一條條的opcode,其實opcode對應的是一個C函數,執行一條opcode就是執行這條opcode對應的C函數,而這個C函數已經被編譯為機器碼了


推薦閱讀:

能在郵件中嵌入PHP嗎?
如何反駁服務端程序員聲稱SELECT出來的數據直接丟給客戶端的代碼最好?
xlsx格式規範,不知類似文件應該從哪找?
樹莓派集群,若要達到與伺服器相同的性能,需要多少個樹莓派?
IT 公司需要前後端都懂的人嗎?

TAG:PHP | 解釋器 | 編譯原理 | PHP開發 |