PHP核心探索:Zend虛擬機器

來源:互聯網
上載者:User
通過前面的學習,我們瞭解到一個PHP檔案在伺服器端的執行過程包括以下兩個大的過程:

  1. 遞給php程式需要執行的檔案, php程式完成基本的準備工作後啟動PHP及Zend引擎, 載入註冊的擴充模組。
  2. 初始化完成後讀取指令檔,Zend引擎對指令檔進行詞法分析,文法分析。然後編譯成opcode執行。 如過安裝了apc之類的opcode緩衝, 編譯環節可能會被跳過而直接從緩衝中讀取opcode執行。

在第二步中,詞法分析、文法分析,編譯中間代碼,執行中間代碼等各個部分統稱為Zend虛擬機器。 與Java、C#等編譯型語言相比,PHP少了一個手動編譯的過程,它們無需編譯即可運行,我們稱其為解釋性語言。 Java有自己的Java虛擬機器,它在多個平台上實現統一語言; C#有自己的.NET虛擬機器,它在單一平台實現多種語言; PHP跟他們一樣,也有屬於自己的Zend虛擬機器。它們在本質是相同的,它們都是抽象的電腦。 這些虛擬機器都是在某種較底層的語言上抽象出另外一種語言,有自己的指令集,有自己的記憶體管理體系。 它們最終都會將抽象層級較高的語言實現轉化為抽象層級較低的語言實現, 並且實現其它協助工具功能,如記憶體管理,記憶體回收等機制, 以減少程式員在具體實現上的工作,從而可以將更多的時間和精力投入到商務邏輯中。 從抽象層次看,Zend虛擬機器比Java等語言更進階一些,這裡的進階不是說功能更強大或效率更高, 簡單點說,Zend虛擬機器離真正的機器實現更遠一些。 最近這些年,語言的發展只是不斷的抽象,不斷的遠離機器,沒有根本性的變化。

這裡我們從虛擬機器的前世今生講起,敘述Zend虛擬機器的實現原理,關鍵的資料結構, 並其中穿插一個關於文法實現的樣本和源碼加密解密的過程說明。

在wiki中虛擬機器的定義是: 虛擬機器(Virtual Machine),在電腦科學中的體繫結構裡,是指一種特殊的軟體, 他可以在電腦平台和終端使用者之間建立一種環境,而終端使用者則是基於這個軟體所建立的環境來操作軟體。 在電腦科學中,虛擬機器是指可以像真實機器一樣運行程式的電腦的軟體實現。

虛擬機器是一種抽象的電腦,它有自己的指令集,有自己的記憶體管理體系。 在此類虛擬機器上實現的語言比較低抽象層次的語言更加明了,更加簡單易學。

PHP檔案是如何被解析的,產生的中間代碼錶示什麼,產生的中間代碼與實際的PHP代碼是如何對應的,產生的中間代碼如何被執行的? 在執行過程中會將會哪些中間的資料?整個虛擬機器是否可以最佳化?如何最佳化?

Zend虛擬機器體繫結構

從概念層將Zend虛擬機器的實現進行抽象,我們可以將Zend虛擬機器的體繫結構分為:解釋層、執行引擎、中間資料層。

Zend虛擬機器體繫結構圖

當一段PHP代碼進入Zend虛擬機器,它會被執行兩步操作:編譯和執行。 對於一個解釋性語言來說,這是一個創造性的舉動,但是,現在的實現並不徹底。 現在當PHP代碼進入Zend虛擬機器後,它雖然會被執行這兩步操作,但是這兩步操作對於一個常規的執行過程來說卻是連續的, 也就是說它並沒有轉變成和Java這種編譯型語言一樣:產生一個中間檔案存放編譯後的結果。 如果每次執行這樣的操作,對於PHP指令碼的效能來說是一個極大的損失。 雖然有類似於APC,eAccelerator等緩衝解決方案。但是其本質上是沒有變化的,並且不能將兩個步驟分離,各自發展壯大。

解釋層

解釋層是Zend虛擬機器執行編譯過程的位置。它包括詞法解析、文法解析和編譯產生中間代碼三個部分。 詞法分析就是將我們要執行的PHP源檔案,去掉空格,去掉注釋,切分為一個個的標記(token), 並且處理常式的層級結構(hierarchical structure)。

文法分析就是將接受的標記(token)序列,根據定義的文法規則,來執行一些動作,Zend虛擬機器現在使用的Bison使用巴科斯範式(BNF) 來描述文法。 編譯產生中間代碼是根據文法解析的結果對照Zend虛擬機器制定的opcode產生中間代碼, 在PHP5.3.1中,Zend虛擬機器支援135條指令(見Zend/zend_vm_opcodes.h檔案), 無論是簡單的輸出語句還是程式複雜的遞迴調用,Zend虛擬機器最終都會將所有我們編寫的PHP代碼轉化成這135條指令的序列, 之後在執行引擎中按順序執行。

中間資料層

當Zend虛擬機器執行一個PHP代碼時,它需要記憶體來儲存許多東西, 比如,中間代碼,PHP內建的函數列表,使用者定義的函數列表,PHP內建的類,使用者自訂的類, 常量,程式建立的對象,傳遞給函數或方法的參數,傳回值,局部變數以及一些運算的中間結果等。 我們把這些所有的存放資料的地方稱為中間資料層。

如果PHP以mod擴充的方式依附於Apache2伺服器運行,中間資料層的部分資料可能會被多個線程共用,如果PHP內建的函數列表等。 如果只考慮單個進程的方式,當一個進程被建立時它就會被載入PHP內建的各種函數列表,類列表,常量列表等。 當解釋層將PHP代碼編譯完成後,各種使用者自訂的函數,類或常量會添加到之前的列表中, 只是這些函數在其自身的結構中某些欄位的賦值是不一樣的。

當執行引擎執行產生的中間代碼時,會在Zend虛擬機器的棧中添加一個新的執行中間資料結構(zend_execute_data), 它包括當前執行過程的活動符號列表的快照、一些局部變數等。

執行引擎

Zend虛擬機器的執行引擎是一個非常簡單的實現,它只是依據中間代碼序列(EX(opline)),一步一步調用對應的方法執行。 在執行引擎中沒並有類似於PC寄存器一樣的變數存放下一條指令,當Zend虛擬機器執行到某條指令時,當它所有的任務都執行完了, 這條指令會自己調用下一條指令,即將序列的指標向前移動一個位置,從而執行下一條指令,並且在最後執行return語句,如此反覆。 這在本質上是一個函數嵌套調用。

回到開頭的問題,PHP通過詞法分析、文法分析和中間代碼產生三個步驟後,PHP檔案就會被解析成PHP的中間代碼opcode。 產生的中間代碼與實際的PHP代碼之間並沒有完全的一一對應關係。只是針對使用者所給的PHP代碼和PHP的文法規則和一些內部約定產生中間代碼, 並且這些中間代碼還需要依靠一些全域變數中轉資料和關聯。至於產生的中間代碼的執行過程是依據中間代碼的順利, 依賴於執行過程中的全域變數,一步步執行。當然,在遇到一些函數跳轉也會發生位移,但是最終還是會回到位移點。

延伸閱讀

此文章所在專題列表如下:

  1. PHP核心探索:從SAPI介面開始
  2. PHP核心探索:一次請求的開始與結束
  3. PHP核心探索:一次請求生命週期
  4. PHP核心探索:單進程SAPI生命週期
  5. PHP核心探索:多進程/線程的SAPI生命週期
  6. PHP核心探索:Zend引擎
  7. PHP核心探索:再次探討SAPI
  8. PHP核心探索:Apache模組介紹
  9. PHP核心探索:通過mod_php5支援PHP
  10. PHP核心探索:Apache運行與鉤子函數
  11. PHP核心探索:嵌入式PHP
  12. PHP核心探索:PHP的FastCGI
  13. PHP核心探索:如何執行PHP指令碼
  14. PHP核心探索:PHP指令碼的執行細節
  15. PHP核心探索:作業碼OpCode
  16. PHP核心探索:PHP裡的opcode
  17. PHP核心探索:解譯器的執行過程
  18. PHP核心探索:變數概述
  19. PHP核心探索:變數儲存與類型
  20. PHP核心探索:PHP中的雜湊表
  21. PHP核心探索:理解Zend裡的雜湊表
  22. PHP核心探索:PHP雜湊演算法設計
  23. PHP核心探索:翻譯一篇HashTables文章
  24. PHP核心探索:雜湊碰撞攻擊是什嗎?
  25. PHP核心探索:常量的實現
  26. PHP核心探索:變數的儲存
  27. PHP核心探索:變數的類型
  28. PHP核心探索:變數的值操作
  29. PHP核心探索:變數的建立
  30. PHP核心探索:預定義變數
  31. PHP核心探索:變數的檢索
  32. PHP核心探索:變數的類型轉換
  33. PHP核心探索:弱類型變數的實現
  34. PHP核心探索:靜態變數的實現
  35. PHP核心探索:變數類型提示
  36. PHP核心探索:變數的生命週期
  37. PHP核心探索:變數賦值與銷毀
  38. PHP核心探索:變數範圍
  39. PHP核心探索:詭異的變數名
  40. PHP核心探索:變數的value和type儲存
  41. PHP核心探索:全域變數Global
  42. PHP核心探索:變數類型的轉換
  43. PHP核心探索:記憶體管理開篇
  44. PHP核心探索:Zend記憶體管理器
  45. PHP核心探索:PHP的記憶體管理
  46. PHP核心探索:記憶體的申請與銷毀
  47. PHP核心探索:引用計數與寫時複製
  48. PHP核心探索:PHP5.3的記憶體回收機制
  49. PHP核心探索:記憶體管理中的cache
  50. PHP核心探索:寫時複製COW機制
  51. PHP核心探索:數組與鏈表
  52. PHP核心探索:使用雜湊表API
  53. PHP核心探索:數組操作
  54. PHP核心探索:數組源碼分析
  55. PHP核心探索:函數的分類
  56. PHP核心探索:函數的內部結構
  57. PHP核心探索:函數結構轉換
  58. PHP核心探索:定義函數的過程
  59. PHP核心探索:函數的參數
  60. PHP核心探索:zend_parse_parameters函數
  61. PHP核心探索:函數傳回值
  62. PHP核心探索:形參return value
  63. PHP核心探索:函數調用與執行
  64. PHP核心探索:引用與函數執行
  65. PHP核心探索:匿名函數及閉包
  66. PHP核心探索:物件導向開篇
  67. PHP核心探索:類的結構和實現
  68. PHP核心探索:類的成員變數
  69. PHP核心探索:類的成員方法
  70. PHP核心探索:類的原型zend_class_entry
  71. PHP核心探索:類的定義
  72. PHP核心探索:存取控制
  73. PHP核心探索:繼承,多態與抽象類別
  74. PHP核心探索:魔術函數與延遲綁定
  75. PHP核心探索:保留類與特殊類
  76. PHP核心探索:對象
  77. PHP核心探索:建立對象執行個體
  78. PHP核心探索:對象屬性讀寫
  79. PHP核心探索:命名空間
  80. PHP核心探索:定義介面
  81. PHP核心探索:繼承與實現介面
  82. PHP核心探索:資源resource類型
  83. PHP核心探索:Zend虛擬機器
  84. PHP核心探索:虛擬機器的詞法解析
  85. PHP核心探索:虛擬機器的文法分析
  86. PHP核心探索:中間代碼opcode的執行
  87. PHP核心探索:代碼的加密與解密
  88. PHP核心探索:zend_execute的具體執行過程
  89. PHP核心探索:變數的引用與計數規則
  90. PHP核心探索:新記憶體回收機制說明
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.