推薦(免費):PHP7
一、PHP7語言執行原理
常用的高階語言有很多種,根據運行的方式不同,大體分為兩種:編譯型語言和解釋型語言。
編譯是指在應用程式原始程式執行之前,就將程式原始碼「翻譯」成彙編語言,然後進一步根據軟硬體環境編譯成目標文件。一般稱完成編譯工作的工具為編譯器。
而解釋型語言,在程式執行時才被「翻譯」為機器語言。但是執行一次「翻譯」一次,所以執行效率較低。 解釋器的工作就是解釋型語言中,負責「翻譯」原始碼的程式。
對於一段C語言程式碼,需要經過預編譯、編譯、彙編和鏈接,才能成為可執行的二進位檔案。
以C語言為代表的編譯型語言,程式碼發生更新都要經過上述步驟。
編譯型語言的執行示意:
#對編譯型語言與解釋型語言的區別的理解,立足於來源程式碼被編譯成目標平台CPU指令的時機。對於編譯型語言,編譯結果已經是針對目前CPU體系的指令;而解釋型語言,需要先編譯成中間碼,再經由該解釋型語言的特定虛擬機,翻譯成特定CPU體系的指令被執行。解釋型語言是在運作過程中,翻譯為目標平台的指令。常說解釋型語言“慢”,主要也是慢在這裡。
在PHP 7中,原始碼首先進行詞法分析,將原始碼切割為多個字串單元,分割後的字串稱為Token。而一個獨立的Token是無法表達完整語意的,需經過語法分析階段,將Token轉換為抽象語法樹(簡稱AST)。之後,抽象語法樹被轉換為機器指令執行。在PHP中,這些指令稱為opcode。
第1步:原始碼透過詞法分析得到Token。
第2步:基於語法分析器產生抽象語法樹(AST)。
第3步:抽象語法樹轉換為opcodes(opcode指令集合),PHP解釋執行opcodes。
#1.Token
Token是PHP程式碼被切割成的有意義的標識。 PHP提供了token_get_all()函數來取得PHP程式碼被切割後的Token.。
二維陣列的每個成員陣列的第一個值為Token對應的枚舉值。第二個值為Token對應的原始字串內容。第三個值為程式碼對應的行號。
可見,Token就是一個個的“詞塊”,但是單獨存在的詞塊不能表達完整的語義,還需要藉助規則進行組織串聯。語法分析器就是這個組織者。它會檢查語法,匹配Token,對Token進行關聯。
2.AST
AST是PHP 7版本新功能。在這之前的版本中,PHP程式碼的執行過程中是沒有產生AST這一步驟的。
AST的節點分為多種類型,對應PHP語法。
PHP-Parser工具,它可以用來查看PHP程式碼產生的AST。
注意 PHP-Parser是PHP 7核心作者之一Nikic所寫的將PHP原始碼產生AST的工具。原始碼見https://github.com/nikic/PHP-Parser。
3.opcodes
opcode只是單一指令,opcodes是opcode的集合形式,是PHP執行過程中的中間程式碼。 opcode產生之後由虛擬機器執行。
PHP工程最佳化措施中有一個比較常見的“開啟opcache”,指的就是這裡的opcodes的快取(opcodes cache)。透過省去從原始碼到opcode的階段,引擎可以直接執行快取的opcode,以此
提升效能。
借助vld插件,可以直覺地看到一段PHP程式碼產生的opcode。
opcode是PHP 7定義的一組指令標識,指令對應對應的handler(處理函數)。當虛擬機器呼叫opcode,會找到opcode背後的處理函數,執行真正的處理。
二、核心架構
Zend引擎中包含了編譯器和解譯器,從PHP程式碼到opcode的執行,都由Zend引擎完成。
Zend引擎除了實現了PHP的核心功能,還提供了一套接口,讓PHP可以在更多的場景中使用,如命令列環境、Web環境等。
此架構圖大致分為四大部分。
1)Zend引擎:前文介紹的詞法/語法分析、AST編譯和opcodes的執行均在Zend引擎中實現。此外,PHP的變數設計、記憶體管理、進程管理等也在引擎層實現。引擎為PHP提供了基礎服務,PHP的可靠性和高效能都依賴引擎的基礎支撐。同時,Zend引擎的可擴充性,也是PHP得以大規模應用的重要原因之一。
2)PHP層:Zend引擎為PHP提供基礎能力(如記憶體分配與回收),而來自外部的互動則需要透過PHP層來處理。
3)SAPI:SAPI是Server API的縮寫,其中包含了常見的cli SAPI和fpm SAPI。 PHP定義好輸入/輸出規範,依據此規範與PHP互動的一方都可以稱為Server。
4)擴充部分:Zend引擎提供了核心能力和介面規格。在此基礎上開發的擴展,為PHP程式碼的效能和功能的多樣性提供了更豐富的選項。
三、PHP原始碼目錄
#sapi目錄原始碼
sapi目錄是輸入和輸出層的抽象,是PHP提供對外服務的規格。
PHP程式的輸入可以是來自於命令列的標準輸入,也可以是來自基於cgi/fastcgi協定的網路請求。同理,輸出可以寫到命令列的標準輸出,也可以作為基於cgi/fastcgi協定的網路回應傳回給客戶端。
命令列模式對應的是二進位程式bin/php;內建模組的模式不需要提供二進位程序,作為普通函數供Apache或任意C/C 程式來呼叫即可;CGI模式對應的是二進位程式bin/cgi;FastCGI模式對應的是二進位程式sbin/php-fpm。
幾種常用的SAPI。
1)apache2handler:Apache擴展,編譯後產生動態連結庫,配置到Apache下,當有http請求到Apache時,根據配置會呼叫此動態連結庫,執行PHP程式碼,完成與PHP的交互。
2)cgi-fcgi:編譯後產生支援CGI協定的可執行程序,webserver(通常為Apache或Nginx)透過CGI協定把請求傳給CGI進程,執行程式碼將結果傳回給webserver,退出進程。
3)fpm-fcgi:fpm全稱為FastCGI Process Manager,PHP官方提供的FastCGI進程管理器。以Nginx伺服器為例,當有http協定請求傳送到Nginx伺服器,Nginx依照FastCGI協定把請求交給php-fpm進程處理。
4)cli:Command Line Interface的簡稱,PHP的命令列互動介面。
Zend目錄原始碼
Zend目錄是PHP的核心程式碼。
1.記憶體管理模組
2.垃圾回收
3.陣列實作
main目錄原始碼
main目錄是SAPI層和Zend層的黏合劑。
Zend層實現了PHP腳本的編譯和執行,sapi層實現了輸入和輸出的抽象,main目錄則起到了承上啟動的作用:承上,解析SAPI的請求,分析要執行的腳本文件和參數;啟下,在呼叫Zend引擎之前,完成必要的初始化等工作。
ext目錄原始碼
ext是PHP擴充相關的目錄,常用的array、str、pdo等系列函數都在這裡定義。
TSRM目錄原始碼
PHP在早期更多的是單一進程、單執行緒模型運行的,在後期才引入了執行緒安全機制ZTS(Zend Thread Safety )。
TSRM是Thread Safe Resource Manager的縮寫-執行緒安全資源管理器。
執行緒安全機制主要為了確保共享資源的安全。 PHP的執行緒安全機制簡潔直觀-在多執行緒環境下,為每個執行緒提供獨立的全域變數副本。具體實作是透過TSRM為每個執行緒分配(分配前加鎖)一個獨立ID(自增)作為當前執行緒的全域變數記憶體區索引,在以後的全域變數存取中,實現執行緒之間的完全獨立。
以上是PHP7 原始碼整體框架詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!