日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

【php内核与扩展开发系列】PHP生命周期---启动、终止与模式

發布時間:2024/1/23 php 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【php内核与扩展开发系列】PHP生命周期---启动、终止与模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

啟動與終止

PHP程序的啟動可以看做有兩個概念上的啟動,終止也有兩個概念上的終止。其中一個是PHP作為Apache(拿它舉例,板磚勿扔)的一個模塊的啟動與終止,這次啟動PHP會初始化一些必要數據,比如與宿主Apache有關的,并且這些數據是常駐內存的,終止與之相對。還有一個概念上的啟動就是當Apache分配一個頁面請求過來的時候,PHP會有一次啟動與終止,這也是我們最常討論的一種。

現在我們主要來看一個PHP擴展的生命旅程是怎樣走完這四個過程的。

在最初初始化的時候,就是PHP隨著Apache的啟動而誕生在內存里的時候,它會把自己所有已加載擴展的MINIT方法(全程Module Initialization,是由每個模塊自己定義的函數)都執行一遍。在這個時間里,擴展可以定義一些自己的常量、類、資源等所有會被用戶端的PHP腳本用到的東西。但你要記住,這里定義的東西都會隨著Apache常駐內存,可以被所有請求使用,直到Apache卸載掉PHP模塊。

內核中預置了PHP_MINIT_FUNCTION宏函數,來幫助我們事先這個功能:

//拋棄作者那個例子,書才看兩頁 整那樣的例子太復雜了! //walu是我擴展的名稱 int time_of_minit; //在MINIT()中初始化,在每次頁面請求中輸出,看看是否變化 PHP_MINIT_FUNCTION(walu) {time_of_minit=time(NULL); //我們在MINIT啟動中對它初始化return SUCCESS; //返回SUCCESS代表正常,返回FALIURE就不會加載這個擴展了。 }

當一個頁面到來時候,PHP會迅速開辟一個新的環境,并重新掃描自己的各個擴展,遍歷執行它們各自的RINIT方法(俗稱Request Initialization),這時候一個擴展可能會初始化在本次請求中會使用到的變量等,還會初始化用戶端(即PHP腳本)中的變量之類的,內核預置了PHP_RINIT_FUNCTION()這個宏函數來幫我們實現這個功能:

int time_of_rinit; //在RINIT里初始化,看看每次頁面請求的時候是否變化。 PHP_RINIT_FUNCTION(walu) {time_of_rinit = time(NULL);return SUCCESS; }

好了,現在這個頁面請求執行的差不多了,可能是順利的走到了自己文件的最后,也可能是出師未捷,半道被用戶給die或者exit了,這時候PHP便會啟動回收程序,收拾這個請求留下的爛攤子。它這次會執行所有已加載擴展的RSHUTDOWN(俗稱Request Shutdown)方法,這時候擴展可以抓緊利用內核中的變量表之類的做一些事情,因為一旦PHP把所有擴展的RSHUTDOWN方法執行完,便會釋放掉這次請求使用過的所有東西,包括變量表的所有變量、所有在這次請求中申請的內存等等。

內核預置了PHP_RSHUTDOWN_FUNCTION宏函數來幫助我們實現這個功能

PHP_RSHUTDOWN_FUNCTION(walu) {FILE *fp = fopen("time_rshutdown.txt", "a+");fprintf(fp, "%ld\n", time(NULL)); //讓我們看看是不是每次請求結束都會在這個文件里追加數據fclose(fp);return SUCCESS; }

這四個宏是在walu.c里完成最終實現的,而他們的則是在/main/php.h里被定義的(其實也是調用的別的宏,本節最后我把這幾個宏給展開了,供有需要的人查看)。

好了,現在我們本節內容說完了,下面我們把所有的代碼合在一起,并預測一下應該出現的結果:

//這些代碼都在walu.c里面,不在.h里int time_of_minit; //在MINIT中初始化,在每次頁面請求中輸出,看看是否變化 PHP_MINIT_FUNCTION(walu) {time_of_minit=time(NULL); //我們在MINIT啟動中對他初始化return SUCCESS; }int time_of_rinit; //在RINIT里初始化,看看每次頁面請求的時候是否變化 PHP_RINIT_FUNCTION(walu) {time_of_rinit=time(NULL);return SUCCESS; }PHP_RSHUTDOWN_FUNCTION(walu) {FILE *fp = fopen("cnan/www/erzha/time_rshutdown.txt", "a+"); //請確保文件可寫,否則apache會莫名崩潰fprintf(fp, "%d\n", time(NULL)); //讓我們看看是不是每次請求結束都會在這個文件里追加數據fclose(fp);return SUCCESS; }PHP_MSHUTDOWN_FUNCTION(walu) {FILE *fp = fopen("/cnan/www/erzha/time_mshutdown.txt", "a+");fprintf(fp, "%d\n", time(NULL));return SUCCESS; }//我們在頁面里輸出time_of_minit和time_of_rinit的值 PHP_FUNCTION(walu_test) {php_printf("%d<br />", time_of_minit);php_printf("%d<br />", time_of_rinit);return; }
  • time_of_minit的值每次請求都不變;
  • time_of_rinit的值每次請求都改變;
  • 每次頁面請求結束都會往time_rshutdown.txt中寫入數據。
  • 只有在Apache結束后time_mshutdown.txt才寫入有數據。

啟動模式

一個PHP實例,無論通過HTTP請求調用的,還是從命令行啟動的,都會依次進行Module init、Request init、Request Shutdown、Module shutdown四個過程,當然之間還會執行腳本自己的邏輯。那么兩種init和兩種shutdown各會執行多少次、各自的執行頻率有多少呢?這取決于PHP是用什么SAPI與宿主通信的。最常見的四種方式如下所列:

直接以CLI/CGI模式調用

多進程模式

多線程模式

Embedded(嵌入式,在自己的C程序中調用Zend Engine)

CLI/CGI

CLI 和 CGI的SAPI是相當特殊的,因為這時PHP的生命周期完全在一個單獨的請求中完成。雖然簡單,不過我們以前提過的兩種init和兩種shutdown仍然都會被執行。下圖展示了PHP在這種模式下是怎么工作的:

多進程模式

ps:書是2006年出版的,所以你應該理解作者說多進程是主流

PHP 最常見的工作方式便是編譯成為Apache2的Pre-fork MPM或者Apache1的APXS模式,其他Web服務器也大多用相同的方式工作,在本書后面,把這種方式統一叫做多進程方式。給它起這個名字是有原因的,不是隨便拍拍屁股拍拍腦袋定下來的。當Apache啟動的時候,會立即把自己fork出好幾個子進程,每一個進程都有自己獨立的內存空間,也就代表了有自己獨立的變量、函數等。在每個進程里的PHP的工作方式如下圖所示:

因為是fork出來的,所以各個進程間的數據是彼此獨立,不會受外界的干擾(ps:fork后可以用管道等方式實現進程間通信)。這是一片獨立天地,它允許每個子進程做任何事情,玩七十碼、躲貓貓都沒人管,辦公室拿砍刀玩自殺也沒事,下圖展示了從Apache的視角來看多進程工作模式下的PHP:

多線程模式

隨著時代的進步,PHP越來越多地在多線程模式下工作,就像IIS和isapi和Apache MPM worker(支持混合的多線程多進程的多路處理模塊)。在這種模式下,只有一個服務器進程在運行著,但會同時運行很多線程,這樣可以減少一些資源開銷,像Module init和Module shutdown就只需要運行一次就行了,一些全局變量也只需要初始化一次,因為線程獨具的特質,使得各個請求之間方便的共享一些數據成為可能。

其實多線程與 MINIT、MSHUTDOWN 只執行一次并沒有什么聯系,多進程模式下一樣可以實現。

下圖展示了在這種模式下 PHP 的工作流程:

Embed

Embed SAPI 是一種比較特殊的 SAPI,容許你在 C/C++ 語言中調用 PHP/ZE 提供的函數。并且這種 SAPI 和上面的三種一樣,按 Module Init、Request Init、Rshutdown、mshutdown 的流程執行著。 當然,這只是其中一種情況。因為特定的應用有自己特殊的需求,只是在處理 PHP 腳本這個環節基本一致。

真正令 Emebed 模式獨特的是因為它可能隨時嵌入到某個程序里面去(比如你的?test.exe?里), 然后被當作腳本的一部分在一個請求的時候執行。控制權在 PHP 和原程序間來回傳遞。關于嵌入式的 PHP 在第20章會有應用,到時我們再用實例介紹這個不經常使用的 SAPI。

總結

以上是生活随笔為你收集整理的【php内核与扩展开发系列】PHP生命周期---启动、终止与模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。