PHP運(yùn)行原理和機(jī)制

雖然說 PHP 學(xué)起來相對簡單互广,但是要精通也不是一件簡單的事龄坪,我們除了要知道怎么使用之外,還得知道它的工作原理渔扎。

PHP 是一種適用于 Web 開發(fā)的腳本語言,可以將它看做是一個(gè)用C語言實(shí)現(xiàn)的包含大量組件的軟件框架信轿。

了解 PHP 的底層實(shí)現(xiàn)赞警,有助于我們更好的運(yùn)用它,優(yōu)化我們程序的性能虏两,從而實(shí)現(xiàn)更加強(qiáng)大的功能

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 可以不再考慮如何針對不同應(yīng)用進(jìn)行兼容五芝,而應(yīng)用本身也可以針對自己的特點(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 在遇到連接請求后贱勃,會(huì)先要?jiǎng)?chuàng)建 CGI 的子進(jìn)程,激活一個(gè) CGI 進(jìn)程谤逼,然后處理請求贵扰,處理完后結(jié)束這個(gè)子進(jìn)程,這就是 fork-and-execute 模式流部。

綜上所述戚绕,使用 CGI 方式的服務(wù)器有多少連接請求就會(huì)有多少 CGI 子進(jìn)程,子進(jìn)程反復(fù)加載 會(huì)導(dǎo)致 CGI 性能低下枝冀。當(dāng)用戶請求數(shù)量非常多時(shí)舞丛,會(huì)大量擠占系統(tǒng)的資源,如內(nèi)存果漾、CPU 時(shí)間等球切,造成性能低下。

FastCGI

fast-cgi 是 CGI 的升級版本绒障,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)客戶端請求到達(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í)痕届,請求便處理完成了。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)存中,一旦有請求出現(xiàn)探橱,就立即使用這些空余的子進(jìn)程進(jìn)行處理申屹,這樣就不存在生成子進(jìn)程造成的延遲了绘证。這些服務(wù)器副本在處理完一次 HTTP 請求之后并不立即退出,而是停留在計(jì)算機(jī)中等待下次請求哗讥。對于客戶瀏覽器的請求反應(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构诚,可以在被用戶請求激活后長駐內(nèi)存蚌斩,等待用戶的另一個(gè)請求,還可以在一個(gè) DLL 里設(shè)置多個(gè)用戶請求處理函數(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

我們再來看看 PHP 代碼執(zhí)行所經(jīng)過的流程脑慧。


v2-d2154b05e6a5487f3542fa84563c7342_b.png

圖: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í)粥烁,對應(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ù)制)麻捻。

對于引用型變量纲仍,其要求和非引用型相反,引用賦值的變量間必須是捆綁的贸毕,修改一個(gè)變量就修改了所有捆綁變量郑叠。

點(diǎn)關(guān)注,不迷路

好了各位明棍,以上就是這篇文章的全部內(nèi)容了乡革,能看到這里的人呀,都是人才。之前說過沸版,PHP方面的技術(shù)點(diǎn)很多嘁傀,也是因?yàn)樘嗔耍瑢?shí)在是寫不過來视粮,寫過來了大家也不會(huì)看的太多细办,所以我這里把它整理成了PDF和文檔,如果有需要的可以點(diǎn)這里進(jìn)階PHP月薪30k>>>架構(gòu)師成長路線【視頻蕾殴、面試文檔免費(fèi)獲取】

24020938-0e1d4138a0a22218.png

24020938-7cffd24782dd56f9.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末笑撞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钓觉,更是在濱河造成了極大的恐慌茴肥,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荡灾,死亡現(xiàn)場離奇詭異瓤狐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卧晓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門芬首,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赴捞,“玉大人逼裆,你說我怎么就攤上這事∩庹” “怎么了胜宇?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恢着。 經(jīng)常有香客問我桐愉,道長,這世上最難降的妖魔是什么掰派? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任从诲,我火速辦了婚禮,結(jié)果婚禮上靡羡,老公的妹妹穿的比我還像新娘系洛。我一直安慰自己,他們只是感情好略步,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布描扯。 她就那樣靜靜地躺著,像睡著了一般趟薄。 火紅的嫁衣襯著肌膚如雪绽诚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機(jī)與錄音恩够,去河邊找鬼卒落。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蜂桶,可吹牛的內(nèi)容都是我干的导绷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼屎飘,長吁一口氣:“原來是場噩夢啊……” “哼妥曲!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钦购,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤檐盟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后押桃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葵萎,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年唱凯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了羡忘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡磕昼,死狀恐怖卷雕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情票从,我是刑警寧澤漫雕,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站峰鄙,受9級特大地震影響浸间,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吟榴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一魁蒜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吩翻,春花似錦兜看、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脚作,卻和暖如春葫哗,著一層夾襖步出監(jiān)牢的瞬間缔刹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工劣针, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留校镐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓捺典,卻偏偏與公主長得像鸟廓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子襟己,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • PHP說簡單引谜,但是要精通也不是一件簡單的事。我們除了會(huì)使用之外擎浴,還得知道它底層的工作原理员咽。 PHP是一種適用于we...
    flysharp閱讀 282評論 0 3
  • PHP說簡單,但是要精通也不是一件簡單的事贮预。我們除了會(huì)使用之外贝室,還得知道它底層的工作原理。 PHP是一種適用于we...
    天天在此TTTT閱讀 86評論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月仿吞,有人笑有人哭滑频,有人歡樂有人憂愁,有人驚喜有人失落唤冈,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,523評論 28 53
  • 信任包括信任自己和信任他人 很多時(shí)候峡迷,很多事情,失敗务傲、遺憾凉当、錯(cuò)過枣申,源于不自信售葡,不信任他人 覺得自己做不成,別人做不...
    吳氵晃閱讀 6,181評論 4 8
  • 怎么對待生活,它也會(huì)怎么對你 人都是哭著來到這個(gè)美麗的人間模孩。每個(gè)人從來到塵寰到升入天堂尖阔,整個(gè)生命的歷程都是一本書,...
    靜靜在等你閱讀 4,957評論 1 6