1、PHP7語言執行原理php
經常使用的高級語言有不少種,根據運行的方式不一樣,大致分爲兩種:編譯型語言和解釋型語言。git
編譯是指在應用源程序執行以前,就將程序源代碼「翻譯」成彙編語言,而後進一步根據軟硬件環境編譯成目標文件。通常稱完成編譯工做的工具爲編譯器。github
而解釋型語言,在程序運行時才被「翻譯」爲機器語言。可是執行一次「翻譯」一次,因此執行效率較低。解釋器的工做就是解釋型語言中,負責「翻譯」源代碼的程序。web
對於一段C語言代碼,須要通過預編譯、編譯、彙編和連接,才能成爲可執行的二進制文件。apache
以C語言爲表明的編譯型語言,代碼發生更新都要通過以上步驟。api
第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背後的處理函數,執行真正的處理。
2、內核架構
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代碼的性能和功能的多樣性提供了更豐富的選項。
3、PHP源碼目錄
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目錄是PHP的核心代碼。
1.內存管理模塊
2.垃圾回收
3.數組實現
main目錄是SAPI層和Zend層的黏合劑。
Zend層實現了PHP腳本的編譯和執行,sapi層實現了輸入和輸出的抽象,main目錄則起到了承上啓下的做用:承上,解析SAPI的請求,分析要執行的腳本文件和參數;啓下,調用Zend引擎以前,完成必要的初始化等工做。
ext是PHP擴展相關的目錄,經常使用的array、str、pdo等系列函數都在這裏定義。
PHP在早期更多的是單個進程、單線程模型運行的,在後期才引入了線程安全機制ZTS(Zend Thread Safety)。
TSRM是Thread Safe Resource Manager的縮寫——線程安全資源管理器。
線程安全機制主要爲了保證共享資源的安全。PHP的線程安全機制簡潔直觀——在多線程環境下,爲每一個線程提供獨立的全局變量副本。具體實施是經過TSRM爲每一個線程分配(分配前加鎖)一個獨立ID(自增)做爲當前線程的全局變量內存區索引,在之後的全局變量訪問中,實現線程之間的徹底獨立。