新聞中心

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


咨詢
建站咨詢
