?
? ????? PHP ??? ???? ??? ?? ??
PHP代碼的編譯
PHP是解析型高級語言,事實上從Zend內(nèi)核的角度來看PHP就是一個普通的C程序,它有main函數(shù),我們寫的PHP代碼是這個程序的輸入,然后經(jīng)過內(nèi)核的處理輸出結(jié)果,內(nèi)核將PHP代碼"翻譯"為C程序可識別的過程就是PHP的編譯。
那么這個"翻譯"過程具體都有哪些操作呢?
C程序在編譯時將一行行代碼編譯為機(jī)器碼,每一個操作都認(rèn)為是一條機(jī)器指令,這些指令寫入到編譯后的二進(jìn)制程序中,執(zhí)行的時候?qū)⒍M(jìn)制程序load進(jìn)相應(yīng)的內(nèi)存區(qū)域(常量區(qū)、數(shù)據(jù)區(qū)、代碼區(qū))、分配運(yùn)行棧,然后從代碼區(qū)起始位置開始執(zhí)行,這是C程序編譯、執(zhí)行的簡單過程。
同樣,PHP的編譯與普通的C程序類似,只是PHP代碼沒有編譯成機(jī)器碼,而是解析成了若干條opcode數(shù)組,每條opcode就是C里面普通的struct,含義對應(yīng)C程序的機(jī)器指令,執(zhí)行的過程就是引擎依次執(zhí)行opcode,比如我們在PHP里定義一個變量:$a = 123;,最終到內(nèi)核里執(zhí)行就是malloc一塊內(nèi)存,然后把值寫進(jìn)去。
所以PHP的解析過程任務(wù)就是將PHP代碼轉(zhuǎn)化為opcode數(shù)組,代碼里的所有信息都保存在opcode中,然后將opcode數(shù)組交給zend引擎執(zhí)行,opcode就是內(nèi)核具體執(zhí)行的命令,比如賦值、加減操作、函數(shù)調(diào)用等,每一條opcode都對應(yīng)一個處理handle,這些handler是提前定義好的C函數(shù)。
從PHP代碼到opcode是怎么實現(xiàn)的?最容易想到的方式就是正則匹配,當(dāng)然過程沒有這么簡單。PHP編譯過程包括詞法分析、語法分析,使用re2c、bison完成,舊的PHP版本直接生成了opcode,PHP7新增了抽象語法樹(AST),在語法分析階段生成AST,然后再生成opcode數(shù)組。
PHP編譯階段的基本過程如下圖:
后面兩個小節(jié)將看下 PHP代碼->AST->Opcodes 的具體編譯過程。