新聞中心

創(chuàng)新互聯(lián)建站是一家以網(wǎng)絡(luò)技術(shù)公司,為中小企業(yè)提供網(wǎng)站維護(hù)、成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站備案、服務(wù)器租用、空間域名、軟件開發(fā)、微信小程序開發(fā)等企業(yè)互聯(lián)網(wǎng)相關(guān)業(yè)務(wù),是一家有著豐富的互聯(lián)網(wǎng)運(yùn)營(yíng)推廣經(jīng)驗(yàn)的科技公司,有著多年的網(wǎng)站建站經(jīng)驗(yàn),致力于幫助中小企業(yè)在互聯(lián)網(wǎng)讓打出自已的品牌和口碑,讓企業(yè)在互聯(lián)網(wǎng)上打開一個(gè)面向全國(guó)乃至全球的業(yè)務(wù)窗口:建站歡迎來電:18980820575
PHP 是一種適用于 web 開發(fā)的腳本語言,可以將它看做是一個(gè)用C語言實(shí)現(xiàn)的包含大量組件的軟件框架。
了解 PHP 的底層實(shí)現(xiàn),有助于我們更好的運(yùn)用它,優(yōu)化我們程序的性能,從而實(shí)現(xiàn)更加強(qiáng)大的功能。
PHP 的設(shè)計(jì)理念及特點(diǎn)
PHP 被設(shè)計(jì)為一種適用于 Web 開發(fā)的動(dòng)態(tài)腳本語言,底層完全由C語言實(shí)現(xiàn),它具備以下特點(diǎn)。
- 解釋型:程序一行一行的邊解釋邊運(yùn)行;
- 弱類型:和 C/C++、JAVA、C# 等語言不同,PHP 是一種弱類型的語言。定義 PHP 變量時(shí)不用指明它的類型,它的類型根據(jù)賦值的數(shù)據(jù)自動(dòng)調(diào)整;另外,一個(gè)變量的類型也不是一成不變的,在運(yùn)行過程中可以給變量賦值不同類型的數(shù)據(jù),從而修改變量的類型。這種機(jī)制的靈活性在 Web 開發(fā)中非常方便和高效;
- 多進(jìn)程模型:由于 PHP 是多進(jìn)程模型,不同請(qǐng)求間互不干涉,這樣保證了一個(gè)請(qǐng)求掛掉不會(huì)對(duì)全盤服務(wù)造成影響;當(dāng)然,隨著時(shí)代發(fā)展,PHP 也已經(jīng)支持了多線程模型;
- 使用引擎(Zend) + 組件(ext)的模式降低內(nèi)部耦合;
- 中間層(sapi)隔絕 web server 和 PHP。
PHP 的四層體系
PHP 的核心架構(gòu)如下圖所示:
圖1:PHP的核心架構(gòu)
從上圖可以看出,PHP 從下到上是可以分為 4 層:
1) Zend 引擎(核心)
Zend 引擎整體用C語言實(shí)現(xiàn),是 PHP 的內(nèi)核部分,它負(fù)責(zé)將 PHP 代碼翻譯(詞法、語法解析等一系列編譯過程)為可執(zhí)行的 opcode 操作碼,并實(shí)現(xiàn)相應(yīng)的處理方法、基本的數(shù)據(jù)結(jié)構(gòu)(如 hashtable、oo)、內(nèi)存分配及管理、提供相應(yīng)的 API 方法供外部調(diào)用。
Zend 是一切的核心,所有的外圍功能均圍繞 Zend 實(shí)現(xiàn)。
2) Extensions(擴(kuò)展)
圍繞著 Zend 引擎,Extensions 通過組件化的方式提供各種基礎(chǔ)服務(wù),我們常見的各種內(nèi)置函數(shù)(例如變量操作函數(shù)、字符串操作函數(shù)等)以及標(biāo)準(zhǔn)庫等都是通過 Extensions 來實(shí)現(xiàn)。
用戶也可以根據(jù)需要實(shí)現(xiàn)自己的 Extension 組件以達(dá)到功能擴(kuò)展、性能優(yōu)化等目的,這就是高手常說的“編寫 PHP 擴(kuò)展”。
3) SAPI(服務(wù)器應(yīng)用程序編程接口)
SAPI 全稱是 Server Application Programming Interface,譯為“服務(wù)器應(yīng)用程序編程接口”。
SAPI 通過一系列鉤子函數(shù),使得 PHP 可以和外圍交互數(shù)據(jù),這是 PHP 非常優(yōu)雅和成功的一個(gè)設(shè)計(jì),通過 SAPI 成功的將 PHP 本身和上層應(yīng)用解耦隔離,PHP 可以不再考慮如何針對(duì)不同應(yīng)用進(jìn)行兼容,而應(yīng)用本身也可以針對(duì)自己的特點(diǎn)實(shí)現(xiàn)不同的處理方式。
4) Application(上層應(yīng)用)
這就是我們平時(shí)編寫的 PHP 程序,通過不同的 SAPI 方式得到各種各樣的應(yīng)用模式,例如通過 Web 服務(wù)器實(shí)現(xiàn)網(wǎng)站后臺(tái)、在命令行下以腳本方式運(yùn)行等。
總結(jié)
如果將 PHP 看作一輛汽車,那么車的框架就是 PHP 本身,Zend 是車的引擎(發(fā)動(dòng)機(jī)),Ext 下面的各種組件就是車的輪子,SAPI 可以看做是公路,車可以跑在不同類型的公路上,而一次 PHP 程序的執(zhí)行就是汽車真正跑在公路上。
要想讓汽車跑得快,性能優(yōu)異的引擎+合適的車輪+正確的跑道都是缺一不可的。
PHP 常見的運(yùn)行模式
SAPI 即服務(wù)器應(yīng)用程序編程接口,是 PHP 與其他應(yīng)用交互的接口,PHP 腳本要執(zhí)行有很多方式,比如通過 Web 服務(wù)器、命令行下或者嵌入在其他程序中。
SAPI 提供了一個(gè)和外部通信的接口,常見的 SAPI 有:cgi、fast-cgi、cli、apache 模塊的 DLL、isapi 等。
CGI
CGI 即通用網(wǎng)關(guān)接口(Common Gateway Interface),它是一段程序,通俗的講 CGI 就象是一座橋,把網(wǎng)頁和 WEB 服務(wù)器中的執(zhí)行程序連接起來,它把 HTML 接收的指令傳遞給服務(wù)器的執(zhí)行程序,再把服務(wù)器執(zhí)行程序的結(jié)果返還給 HTML。
CGI 的跨平臺(tái)性能極佳,幾乎可以在任何操作系統(tǒng)上實(shí)現(xiàn)。
CGI 在遇到連接請(qǐng)求后,會(huì)先要?jiǎng)?chuàng)建 CGI 的子進(jìn)程,激活一個(gè) CGI 進(jìn)程,然后處理請(qǐng)求,處理完后結(jié)束這個(gè)子進(jìn)程,這就是 fork-and-execute 模式。
綜上所述,使用 CGI 方式的服務(wù)器有多少連接請(qǐng)求就會(huì)有多少 CGI 子進(jìn)程,子進(jìn)程反復(fù)加載 會(huì)導(dǎo)致 CGI 性能低下。當(dāng)用戶請(qǐng)求數(shù)量非常多時(shí),會(huì)大量擠占系統(tǒng)的資源,如內(nèi)存、CPU 時(shí)間等,造成性能低下。
FastCGI
fast-cgi 是 CGI 的升級(jí)版本,F(xiàn)astCGI 像是一個(gè)常駐(long-live)型的 CGI,它激活后可以一直執(zhí)行著。
FastCGI 的工作原理:
- Web Server 啟動(dòng)時(shí)載入 FastCGI 進(jìn)程管理器(IIS ISAPI 或 Apache Module);
- FastCGI 進(jìn)程管理器自身初始化,啟動(dòng)多個(gè) CGI 解釋器進(jìn)程(可見多個(gè) php-cgi)并等待來自 Web Server 的連接;
- 當(dāng)客戶端請(qǐng)求到達(dá) Web Server 時(shí),F(xiàn)astCGI 進(jìn)程管理器選擇并連接到一個(gè) CGI 解釋器。Web server 將 CGI 環(huán)境變量和標(biāo)準(zhǔn)輸入發(fā)送到 FastCGI子進(jìn)程 php-cgi;
- FastCGI 子進(jìn)程完成處理后將標(biāo)準(zhǔn)輸出和錯(cuò)誤信息從同一連接返回 Web Server。當(dāng) FastCGI 子進(jìn)程關(guān)閉連接時(shí),請(qǐng)求便處理完成了。FastCGI 子進(jìn)程接著等待并處理來自 FastCGI 進(jìn)程管理器(運(yùn)行在 Web Server 中)的下一個(gè)連接。 在 CGI 模式中,php-cgi 在此便退出了。
APACHE2HANDLER
PHP 作為 Apache 的模塊,Apache 服務(wù)器在系統(tǒng)啟動(dòng)后,預(yù)先生成多個(gè)進(jìn)程副本駐留在內(nèi)存中,一旦有請(qǐng)求出現(xiàn),就立即使用這些空余的子進(jìn)程進(jìn)行處理,這樣就不存在生成子進(jìn)程造成的延遲了。這些服務(wù)器副本在處理完一次 HTTP 請(qǐng)求之后并不立即退出,而是停留在計(jì)算機(jī)中等待下次請(qǐng)求。對(duì)于客戶瀏覽器的請(qǐng)求反應(yīng)更快,性能較高。
apache 模塊的 DLL
該運(yùn)行模式是我們以前在 windows 環(huán)境下使用 apache 服務(wù)器經(jīng)常使用的,而在模塊化(DLL)中,PHP 是與 Web 服務(wù)器一起啟動(dòng)并運(yùn)行的。(是 apache 在 CGI 的基礎(chǔ)上進(jìn)行的一種擴(kuò)展,可以加快 PHP 的運(yùn)行效率)
ISAPI
ISAPI 即 Internet Server Application Program Interface,是微軟提供的一套面向 Internet 服務(wù)的 API 接口。一個(gè) ISAPI 的 DLL,可以在被用戶請(qǐng)求激活后長(zhǎng)駐內(nèi)存,等待用戶的另一個(gè)請(qǐng)求,還可以在一個(gè) DLL 里設(shè)置多個(gè)用戶請(qǐng)求處理函數(shù),此外 ISAPI 的 DLL 應(yīng)用程序和 WWW 服務(wù)器處于同一個(gè)進(jìn)程中,效率要顯著高于 CGI。
CLI
CLI(全稱:command-line interface)命令行界面,是在圖形用戶界面得到普及之前使用最為廣泛的用戶界面,它通常不支持鼠標(biāo),用戶通過鍵盤輸入指令,計(jì)算機(jī)接收到指令后,予以執(zhí)行。也有人稱之為字符用戶界面(CUI)。
PHP 的執(zhí)行流程和 opcode
我們?cè)賮砜纯?PHP 代碼執(zhí)行所經(jīng)過的流程。
圖2:PHP 的執(zhí)行流程
一段PHP代碼會(huì)經(jīng)過詞法解析、語法解析等階段,會(huì)被翻譯成一個(gè)個(gè)指令(opcode),然后 zend 虛擬機(jī)會(huì)順序執(zhí)行這些指令。PHP 本身是用C語言實(shí)現(xiàn)的,因此最終調(diào)用的也是C語言的函數(shù),實(shí)際上我們可以把 PHP 看做一個(gè)C語言開發(fā)的軟件。
PHP 執(zhí)行的核心就是翻譯出來的一條一條指令,也就是 opcode,opcode 是 PHP 程序執(zhí)行的最基本單位。
在計(jì)算機(jī)科學(xué)領(lǐng)域中,操作碼(Operation Code)被用于描述機(jī)器語言指令中,指定要執(zhí)行某種操作的那部分機(jī)器碼,構(gòu)成 opcode 的指令格式和規(guī)范由處理器的指令規(guī)范指定。
一個(gè) opcode 由兩個(gè)參數(shù)(op1,op2)、返回值和處理函數(shù)組成。PHP 程序最終被翻譯為一組 opcode 處理函數(shù)的順序執(zhí)行。
下面列舉了幾個(gè)常見的處理函數(shù):
- ZEND_ASSIGN_SPEC_CV_CV_HANDLER : 變量分配 ($a=$b);
- ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER:函數(shù)調(diào)用;
- ZEND_CONCAT_SPEC_CV_CV_HANDLER:字符串拼接 $a.$b;
- ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法運(yùn)算 $a+2;
- ZEND_IS_EQUAL_SPEC_CV_CONST:判斷相等 $a==1;
- ZEND_IS_IDENTICAL_SPEC_CV_CONST:判斷相等 $a===1。
HashTable
HashTable是Zend的核心數(shù)據(jù)結(jié)構(gòu),在PHP里面幾乎并用來實(shí)現(xiàn)所有常見功能,我們知道的PHP數(shù)組即是其典型應(yīng)用,此外在zend內(nèi)部,如函數(shù)符號(hào)表、全局變量等也都是基于HashTable。
HashTable具有如下特點(diǎn):
- 支持典型的key->value查詢;
- 可以當(dāng)做數(shù)組使用;
- 添加、刪除節(jié)點(diǎn)是O(1)復(fù)雜度;
- key支持混合類型,同時(shí)存在關(guān)聯(lián)數(shù)組合索引數(shù)組;
- Value支持混合類型:array("string",2332);
- 支持線性遍歷,如 foreach。
Zval
由于PHP 是一門弱類型語言,本身不嚴(yán)格區(qū)分變量的類型。PHP 在聲明變量的時(shí)候不需要指定類型。PHP 在程序運(yùn)行期間可能進(jìn)行變量類型的隱式轉(zhuǎn)換。和其他強(qiáng)類型語言一樣,程序中也可以進(jìn)行顯式的類型轉(zhuǎn)換。Zval 是 Zend 中另一個(gè)非常重要的數(shù)據(jù)結(jié)構(gòu),用來標(biāo)識(shí)并實(shí)現(xiàn) PHP 變量。
Zval 主要由以下 3 部分組成。
- Type:指定了變量所述的類型(整數(shù)、字符串、數(shù)組等);
- refcount&is_ref:用來實(shí)現(xiàn)引用計(jì)數(shù);
- value:是核心部分,存儲(chǔ)了變量的實(shí)際數(shù)據(jù)。
Zval 用來保存一個(gè)變量的實(shí)際數(shù)據(jù)。因?yàn)橐鎯?chǔ)多種類型,所以 zval 是一個(gè) union,也由此實(shí)現(xiàn)了弱類型。
引用計(jì)數(shù)在內(nèi)存回收、字符串操作等地方使用得非常廣泛。PHP 中的變量就是引用計(jì)數(shù)的典型應(yīng)用。Zval 的引用計(jì)數(shù)通過成員變量 is_ref 和 ref_count 實(shí)現(xiàn)。通過引用計(jì)數(shù),多個(gè)變量可以共享同一份數(shù)據(jù),避免頻繁復(fù)制帶來的大量消耗。
在進(jìn)行賦值操作時(shí),Zend 將變量指向相同的 Zval,同時(shí) ref_count++,在 unset 操作時(shí),對(duì)應(yīng)的 ref_count-1。只有 ref_count 為 0 時(shí)才會(huì)真正執(zhí)行銷毀操作。如果是引用賦值,Zend 就會(huì)修改 is_ref 為 1。
PHP 變量通過引用計(jì)數(shù)實(shí)現(xiàn)變量共享數(shù)據(jù),當(dāng)試圖寫入一個(gè)變量時(shí),Zend 若發(fā)現(xiàn)該變量指向的 Zval 被多個(gè)變量共享,則為其復(fù)制一份 ref_count 為 1 的 Zval,并遞減原 Zval 的 refcount,這個(gè)過程稱為“Zval分離”。可見,只有在有寫操作發(fā)生時(shí),Zend 才進(jìn)行復(fù)制操作,因此也叫 copy-on-write(寫時(shí)復(fù)制)。
對(duì)于引用型變量,其要求和非引用型相反,引用賦值的變量間必須是捆綁的,修改一個(gè)變量就修改了所有捆綁變量。
本文標(biāo)題:PHP運(yùn)行原理和機(jī)制
瀏覽路徑:http://www.dlmjj.cn/article/dhidepi.html


咨詢
建站咨詢
