1,、PHP的運行模式:PHP兩種運行模式是WEB模式,、CLI模式。無論哪種模式,,PHP工作原理都是一樣的,,作為一種SAPI運行,。 1、當我們在終端敲入php這個命令的時候,,它使用的是CLI,。 它就像一個web服務器一樣來支持php完成這個請求,請求完成后再重新把控制權交給終端,。 2,、當使用Apache或者別web服務器作為宿主時,當一個請求到來時,,PHP會來支持完成這個請求,。一般有:
多進程(通常編譯為apache的模塊來處理PHP請求) 多線程模式 2、一切的開始: SAPI接口通常我們編寫php Web程序都是通過Apache或者Nginx這類Web服務器來測試腳本. 或者在命令行下通過php程序來執(zhí)行PHP腳本. 執(zhí)行完成腳本后,,服務器應答,瀏覽器顯示應答信息,或者在命令結束后在標準輸出顯示內容. 我們很少關心PHP解釋器在哪里. 雖然通過Web服務器和命令行程序執(zhí)行腳本看起來很不一樣. 實際上她們的工作是一樣的. 命令行程序和Web程序類似, 命令行參數(shù)傳遞給要執(zhí)行的腳本,相當于通過url 請求一個PHP頁面. 腳本戳里完成后返回響應結果,只不過命令行響應的結果是顯示在終端上. 腳本執(zhí)行的開始都是通過SAPI接口進行的. 1),、啟動apache:當給定的SAPI啟動時,,例如在對/usr/local/apache/bin/apachectl start的響應中,PHP由初始化其內核子系統(tǒng)開始,。在接近啟動例程的末尾,,它加載每個擴展的代碼并調用其模塊初始化例程(MINIT)。這使得每個擴展可以初始化內部變量,、分配資源,、注冊資源處理器,以及向ZE注冊自己的函數(shù),,以便于腳本調用這其中的函數(shù)時候ZE知道執(zhí)行哪些代碼,。 2)、請求處理初始化:接下來,,PHP等待SAPI層請求要處理的頁面,。對于CGI或CLI等SAPI,這將立刻發(fā)生且只發(fā)生一次,。對于Apache,、IIS或其他成熟的web服務器SAPI,每次遠程用戶請求頁面時都將發(fā)生,,因此重復很多次,,也可能并發(fā)。不管請求如何產生,,PHP開始于要求ZE建立腳本的運行環(huán)境,,然后調用每個擴展的請求初始化 (RINIT)函數(shù)。RINIT使得擴展有機會設定特定的環(huán)境變量,,根據(jù)請求分配資源,,或者執(zhí)行其他任務,,如審核。 session擴展中有個RINIT作用的典型示例,,如果啟用了session.auto_start選項,,RINIT將自動觸發(fā)用戶空間的session_start()函數(shù)以及預組裝$_SESSION變量。 3),、執(zhí)行php代碼: 一旦請求被初始化了,,ZE開始接管控制權,將PHP腳本翻譯成符號,,最終形成操作碼并逐步運行之,。如任一操作碼需要調用擴展的函數(shù),ZE將會把參數(shù)綁定到該函數(shù),,并且臨時交出控制權直到函數(shù)運行結束,。 4)、腳本結束:腳本運行結束后,,PHP調用每個擴展的請求關閉(RSHUTDOWN)函數(shù)以執(zhí)行最后的清理工作(如將session變量存入磁盤),。接下來,ZE執(zhí)行清理過程(垃圾收集)-有效地對之前的請求期間用到的每個變量執(zhí)行unset(),。 5),、sapi關閉:一旦完成,PHP繼續(xù)等待SAPI的其他文檔請求或者是關閉信號,。對于CGI和CLI等SAPI,,沒有“下一個請求”,所以SAPI立刻開始關閉,。關閉期間,,PHP再次遍歷每個擴展,調用其模塊關閉(MSHUTDOWN)函數(shù),,并最終關閉自己的內核子系統(tǒng),。 簡要的過程如下:
1. PHP是隨著Apache的啟動而運行的; 3,、PHP的開始和結束階段開始階段有兩個過程:第一個過程:apache啟動的過程,,即在任何請求到達之前就發(fā)生。是在整個SAPI生命周期內(例如Apache啟動以后的整個生命周期內或者命令行程序整個執(zhí)行過程中)的開始階段(MINIT),該階段只進行一次.,。啟動Apache后,,PHP解釋程序也隨之啟動; PHP調用各個擴展(模塊)的MINIT方法,,從而使這些擴展切換到可用狀態(tài),??纯磒hp.ini文件里打開了哪些擴展吧,; MINIT的意思是“模塊初始化”。各個模塊都定義了一組函數(shù),、類庫等用以處理其他請求,。 模塊在這個階段可以進行一些初始化工作,例如注冊常量, 定義模塊使用的類等等.典型的的模塊回調函數(shù)MINIT方法如下:
第二個過程發(fā)生在請求階段,當一個頁面請求發(fā)生時.則在每次請求之前都會進行初始化過程(RINIT請求開始). 請求到達之后,SAPI層將控制權交給PHP層,,PHP初始化本次請求執(zhí)行腳本所需的環(huán)境變量,例如創(chuàng)建一個執(zhí)行環(huán)境,包括保存php運行過程中變量名稱和變量值內容的符號表. 以及當前所有的函數(shù)以及類等信息的符號表.例如是Session模塊的RINIT,,如果在php.ini中啟用了Session 模塊,那在調用該模塊的RINIT時就會初始化$_SESSION變量,,并將相關內容讀入,; 然后PHP會調用所有模塊RINIT函數(shù),即“請求初始化”。 在這個階段各個模塊也可以執(zhí)行一些相關的操作, 模塊的RINIT函數(shù)和MINIT函數(shù)類似 ,,RINIT方法可以看作是一個準備過程,,在程序執(zhí)行之間就會自動啟動。
結束階段分為兩個環(huán)節(jié):請求處理完后就進入了結束階段, 一般腳本執(zhí)行到末尾或者通過調用exit()或者die()函數(shù),PHP都將進入結束階段. 和開始階段對應,結束階段也分為兩個環(huán)節(jié),一個在請求結束后(RSHUWDOWN),一個在SAPI生命周期結束時(MSHUTDOWN).
第一個環(huán)節(jié):請求處理完后結束階段:請求處理完后就進入了結束階段,,PHP就會啟動清理程序,。它會按順序調用各個模塊的RSHUTDOWN方法。
RSHUTDOWN用以清除程序運行時產生的符號表,,也就是對每個變量調用unset函數(shù),。典型的RSHUTDOWN方法如下:
第二個環(huán)節(jié):最后,,所有的請求都已處理完畢,SAPI也準備關閉了,, PHP調用每個擴展的MSHUTDOWN方法,,這是各個模塊最后一次釋放內存的機會。(這個是對于CGI和CLI等SAPI,,沒有“下一個請求”,,所以SAPI立刻開始關閉。) 典型的RSHUTDOWN方法如下:
這樣,,整個PHP生命周期就結束了,。要注意的是,只有在服務器沒有請求的情況下才會執(zhí)行“啟動第一步”和“關閉第二步”,。
SAPI運行PHP都經(jīng)過下面幾個階段:
4,、單進程SAPI生命周期
CLI/CGI模式的PHP屬于單進程的SAPI模式,。這類的請求在處理一次請求后就關閉。也就是只會經(jīng)過如下幾個環(huán)節(jié): 開始 - 請求開始 - 請求關閉 - 結束 SAPI接口實現(xiàn)就完成了其生命周期,。如圖所示:
5,、多進程SAPI生命周期
通常PHP是編譯為apache的一個模塊來處理PHP請求。Apache一般會采用多進程模式,, Apache啟動后會 fork出多個子進程,,每個進程的內存空間獨立,每個子進程都會經(jīng)過開始和結束環(huán)節(jié),, 不過每個進程的開始階 段只在進程fork出來以來后進行,,在整個進程的生命周期內可能會處理多個請求。 只有在Apache關閉或者進程 被結束之后才會進行關閉階段,,在這兩個階段之間會隨著每個請求重復請求開始-請求關閉的環(huán)節(jié),。 如圖所示:
6、多線程的SAPI生命周期多線程模式和多進程中的某個進程類似,,不同的是在整個進程的生命周期內會并行的重復著 請求開始-請求關閉的環(huán)節(jié).
在這種模式下,,只有一個服務器進程在運行著,但會同時運行很多線程,這樣可以減少一些資源開銷,,向Module init和Module shutdown就只需要運行一遍就行了,,一些全局變量也只需要初始化一次,因為線程獨具的特質,,使得各個請求之間方便的共享一些數(shù)據(jù)成為可能,。 多線程工作方式如下圖
7、Apache一般使用多進程模式prefork 在linux下使用#http –l 命令可以查看當前使用的工作模式,。也可以使用#apachectl -l命令,。 prefork 進程池模型,,用在 UNIX 和類似的系統(tǒng)上比較多,主要是由于寫起來方便,,也容易移植,,還不容易出問題。要知道,,如果采用線程模型的話,,用戶線程、內核線程和混合型線程有不同的特性,,移植起來就麻煩,。prefork 模型,即預先 fork() 出來一些子進程緩沖一下,,用一個鎖來控制同步,,連接到來了就放行一個子進程,讓它去處理,。
prefork MPM 使用多個子進程,,每個子進程只有一個線程,。每個進程在某個確定的時間只能維持一個連接,。在大多數(shù)平臺上,Prefork MPM在效率上要比Worker MPM要高,,但是內存使用大得多,。prefork的無線程設計在某些情況下將比worker更有優(yōu)勢:他能夠使用那些沒有處理好線程安全的第三方模塊,并 且對于那些線程調試困難的平臺而言,,他也更容易調試一些,。
|
|