【PHP7內核剖析】——PHP的編譯與執行

我們都知道,PHP是一門編譯型語言,那除了編譯型語言,計算機還有什麼語言呢?一般來說,計算機語言分爲兩類,一種就是C/C++等的編譯型語言,另外一種是PHP的解釋型語言。那解釋型語言與編譯型語言有什麼區別呢?那個又更好呢?我們先來扒一扒這兩種語言的解釋吧!

編譯型語言:程序在運行之前先將語言編譯成計算機可執行的二級制文件,在執行時直接執行機器指令。

解釋型語言:程序在運行時有解釋器邊編譯邊執行,又稱腳本語言。

這兩種語言用例子來說的話,我們可以把編譯型語言當作是飯先做好了再喫,而解釋型語言就好比說火鍋,邊涮邊喫!

編譯型語言不是咱們的重點,咱們不多說,說說PHP這種解釋型語言吧。前面說過,解釋型語言是用解釋器邊編譯邊執行的,那麼,PHP的解釋器是什麼呢?ZendVM。就和Java中的JVM一樣,ZendVM就是PHP語言的解釋器,這也是整合PHP內核中最爲核心的地方。一個PHP程序運行的過程爲:

從上面我們可以看到,PHP語言與計算機之間多了一層解釋器,這個解釋器完美的解決了跨平臺的問題,使得PHP這種解釋型語言可以任意跨平臺開發,但是,這也導致瞭解釋型語言的效率遠遠不如編譯型語言。而且,同樣的計算,解釋型語言往往比編譯型語言需要執行更多的指令來完成!由此來看,這兩種語言也沒有誰更好的說法,只能說是你的項目更適合使用什麼語言了。

接下來我們繼續探究PHP的層面。上面說到了ZendVM是PHP中內核中最爲核心的部分,那我們就來深入的研究一下ZendVM這個虛擬機。ZendVM有兩部分組成:編譯器與執行器。其中編譯器負責將PHP代碼解釋成ZendVM可識別的指令(opline),執行器負責執行opline中的opcode對應的機器指令。

先看一下opline的結構:

struct _zend_op {
	const void *handler;
	znode_op op1;
	znode_op op2;
	znode_op result;
	uint32_t extended_value;
	uint32_t lineno;
	zend_uchar opcode;
	zend_uchar op1_type;
	zend_uchar op2_type;
	zend_uchar result_type;
};

整個opline的結構我們可以分成兩部分來看,前面是opline的操作數,後面是處理動作。

其中op1,op2,result分別指的是操作數1,操作數2,返回值。opcode爲指令編碼,唯一標識一個指令動作。目前PHP總共定義了173條opcode,我們常用的賦值,循環,判斷等都在這173條opcode中。handle爲每條opcode對應的實際處理函數。

通過上面的學習,我們已經知道了opline是一條指令,那麼多條指令呢?PHP中定義了一個zend_op_array結構保存多個編譯生成的數據。

接下來我們來看一下PHP的編譯。配合拍的編譯過程就是將PHP腳本代碼轉成opcode指令的過程。具體爲:

其中,在詞法分析,語法分析階段,分別使用re2c詞法掃描器與yacc語法分析器。抽象語法樹的編譯就是生成ZendVM可識別的指令。語法分析之後,ZendVM會把抽象語法樹進一步編譯成zend_op_array。

再我們來看一下PHP的執行。ZendVM執行器有指令處理headler與調度器組合而成。執行時,有執行器調用相應的handler完成指令的處理;調度器負責控制指令的執行,以及執行器上下文的切換,有調度器發起handler的執行。

總結:目前本人對這快的理解深度還不夠,後面需要重新找時間在深入源碼研讀一下原理。如果正好你也感興趣的話,歡迎隨時騷擾,咱們一起探討,一起學習!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章