首先開始介紹php的生命週期,瞭解一個php程式從開始運行到最後結束究竟經過怎麼樣的過程,對學習php和平時php開發應該是很重要的。
起始和關閉階段:
- 對於php的起始和關閉階段可以分成兩層,
- 第一層是php解譯器作為一個整體進行結構和值的初始化過程。
- 第二層則是在每一個頁面的請求過程中。
- 對於每個擴充而言,都會有一個初始化MINT函數,這個過程會聲明變數、類,註冊資源、流和過濾處理器,這些操作在所有的請求中都是存在的,所以可以稱為是Persistent的。一般進行如下的兩步操作:
- REGISTER_INI_ENTRIES()
- 初始化模組的全域變數
- 而在頁面發出請求了之後,PHP則會建立一個包括符號表和配置值在內的作業環境,然後這次php解譯器會再次迴圈每一個擴充,調用每個擴充的RINIT初始化函數。一般RINT函數的操作如下:
- 把globalvalue設成預設值,這些全域變數往往是每個請求都需要的,但是針對每一個請求而言都是相互獨立的。
- 那些需要用到的變數需要放到符號表中以備調用。
- 在這個函數中還可以記錄一下請求的相關資訊
- 完成了請求的處理之後,如果到達了指令碼尾部或通過die() exit()推出了,那麼php通過調用RSHUTDOWN()開始清理
- 這時候每個符號表中的變數都會被unset掉
- 而當所有的請求都被滿足了之後,就開始針對於模組的MSHUTDOWN過程
- 調用UNREGISTER_INI_ENTRYES(),與MINIT函數的初始化過程相互對應。php程式執行的生命週期:
要瞭解生命週期,就必須對不同的執行方式有所涉及。php可以有幾種不同的執行方式,每種方式都有其特定的生命週期。
- CLI:這個是從命令列執行php程式,它的生命週期最為簡單。比如在執行test.php的時候,就經曆了如下的過程
- 圖1 CLI進行php執行的過程
- 注意到MINIT RINIT RSHUTDOWN MSHUTDOWN都只被調用過一次,這個比較類似於瀑布式的結構。
- 多線程的模組方式:這是最常用的一種方式,php作為APXS的模組對apache進行配合。在apache啟動的時候會fork很多的子進程。針對於多個不同的請求,配合的是多個不同的初始化與結束過程。但是對每一個線程來說,只有一個MINIT和MSHUTDOWN的調用。而每個請求都對應著自己單獨的RINIT和RSHUTDOWN。
- 多線程的模組方式:採用多線程的方法可以避免不同的線程重複的調用MINIT/MSHUTDOWN.它具有的好處是多個請求可以共用資訊,但是請求之間的隔離要求比較高,不然容易出現變數的訪問出錯。
Zend 安全執行緒
php對安全執行緒的處理有專門的機制,稱為Thread Safe Resource Management(TSRM)。在進行安全執行緒和非安全執行緒聲明的時候,明顯有一些不同之處:
- 安全執行緒的變數聲明:
- typedef struct {
int sampleint;
char *samplestring;
} php_sample_globals;
int sample_globals_id;
PHP_MINIT_FUNCTION(sample)
{
ts_allocate_id(&sample_globals_id,
sizeof(php_sample_globals),
(ts_allocate_ctor) php_sample_globals_ctor,
(ts_allocate_dtor) php_sample_globals_dtor);
return SUCCESS;
}
- 從這段代碼中可以看到,在MINIT階段,需要通過ts_allocate_id函數來通知TSRM這個程式需要多少空間,TSRM會增加當前的空間消耗,並返回一個id指向線程資料池的相應部分。
- 而當請求要訪問資料的時候,就首先從TSRM層找到當前線程的資源集區的指標,然後加上ts_allocate_id()返回的資源id作為offset。
- 非安全執行緒的變數聲明:
- typedef struct {
int sampleint;
char *samplestring;
} php_sample_globals;
php_sample_globals sample_globals;
PHP_MINIT_FUNCTION(sample)
{
php_sample_globals_ctor(&sample_globals TSRMLS_CC);
return SUCCESS;
}