# 1.3 PHP的生命周期
# 1.3 PHP的生命周期
一個PHP實例,無論通過http請求調用的,還是從命令行啟動的,都會向我們上一節說的那樣, 依次進行Module init、Request init、Request Shutdown、Module shutdown四個過程, 當然之間還會執行腳本自己的邏輯。 那么兩種init和兩種shutdown各會執行多少次、各自的執行頻率有多少呢? 這取決于PHP是用什么sapi與宿主通信的。最常見的四種方式如下所列:
- 直接以CLI/CGI模式調用
- 多進程模式
- 多線程模式
- Embedded(嵌入式,在自己的C程序中調用Zend Engine)
## 1、CLI/CGI
CLI和CGI的SAPI是相當特殊的,因為這時PHP的生命周期完全在一個單獨的請求中完成。雖然簡單,不過我們以前提過的兩種init和兩種shutdown仍然都會被執行。圖1.1展示了PHP在這種模式下是怎么工作的。

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

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

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

## 4、Embed
Embed SAPI是一種比較特殊的sapi,容許你在C/C++語言中調用PHP/ZE提供的函數。 并且這種sapi和上面的三種一樣,按Module Init、Request Init、Rshutdown、mshutdown的流程執行著。 當然,這只是其中一種情況。因為特定的應用有自己特殊的需求,只是在處理PHP腳本這個環節基本一致。
真正令emebed模式獨特的是因為它可能隨時嵌入到某個程序里面去(**比如你的test.exe里**), 然后被當作腳本的一部分在一個請求的時候執行。 控制權在PHP和原程序間來回傳遞。關于嵌入式的PHP在第20章會有應用,到時我們再用實例介紹這個不經常使用的sapi。
## 關于Embed SAPI應用的文章
- [Laruence大哥的使用PHP Embed SAPI實現Opcodes查看器](http://www.laruence.com/2008/09/23/539.html) </li>
## links
- [目錄](preface.md)
- 上一節 [PHP的啟動與終止](1.2.html)
- 下一節 [線程安全](1.4.html)
- 介紹
- 1 PHP的生命周期
- 1.1 讓我們從SAPI開始
- 1.2 PHP的啟動與終止
- 1.3 PHP的生命周期
- 1.4 線程安全
- 1.5 PHP的生命周期
- 2 PHP變量在內核中的實現
- 2.1 變量的類型
- 2.2 變量的值
- 2.3 創建PHP變量
- 2.4 變量的存儲方式
- 2.5 變量的檢索
- 2.6 類型轉換
- 2.7 小結
- 3 內存管理
- 3.1 內存管理
- 3.2 引用計數
- 3.3 內存管理
- 4 動手編譯PHP
- 4.1 動手編譯PHP
- 4.2 動手編譯PHP
- 4.3 Unix/Linux平臺下的編譯
- 4.4 在Win32平臺上編譯PHP
- 4.5 動手編譯PHP
- 5 Your First Extension
- 5.1 Your First Extension
- 5.2 編譯我們的擴展
- 5.3 靜態編譯
- 5.4 編寫函數
- 5.5 Your First Extension
- 6 函數返回值
- 6.1 函數返回值
- 6.2 引用與函數的執行結果
- 6.3 函數返回值
- 7 函數的參數
- 7.1 函數的參數
- 7.2 函數的參數
- 7.3 函數的參數
- 8 使用HashTable與{數組}
- 8.1 使用HashTable與{數組}
- 8.2 使用HashTable與{數組}
- 8.3 使用HashTable與{數組}
- 8.4 使用HashTable與{數組}
- 9 PHP中的資源類型
- 9.1 PHP中的資源類型
- 9.2 PHP中的資源類型
- 9.3 PHP中的資源類型
- 9.4 PHP中的資源類型
- 10 PHP中的面向對象(一)
- 10.1 PHP中的面向對象(一)
- 10.2 PHP中的面向對象(一)
- 10.3 PHP中的面向對象(一)
- 10.4 PHP中的面向對象(一)
- 10.5 PHP中的面向對象(一)
- 11 PHP中的面向對象(二)
- 11.1 PHP中的面向對象(二)
- 11.2 PHP中的面向對象(二)
- 11.3 PHP中的面向對象(二)
- 12 啟動與終止的那點事
- 12.1 關于生命周期
- 12.2 MINFO與phpinfo
- 12.3 常量
- 12.4 PHP擴展中的全局變量
- 12.5 PHP語言中的超級全局變量(Superglobals)
- 12.6 小結
- 13 INI設置
- 13.1 聲明和訪問INI設置
- 13.2 小結
- 14 流式訪問
- 14.1 流的概覽
- 14.2 訪問流
- 14.3 靜態資源操作
- 14.4 links
- 15 流的實現
- 15.1 php流的表象之下
- 15.2 包裝器操作
- 15.3 實現一個包裝器
- 15.4 操縱
- 15.5 檢查
- 15.6 小結
- 16 有趣的流
- 16.1 上下文
- 16.2 過濾器
- 16.3 小結
- 17 配置和鏈接
- 17.1 autoconf
- 17.2 庫的查找
- 17.3 強制模塊依賴
- 17.4 Windows方言
- 17.5 小結
- 18 擴展生成
- 18.1 ext_skel
- 18.2 PECL_Gen
- 18.3 小結
- 19 設置宿主環境
- 19.1 嵌入式SAPI
- 19.2 構建并編譯一個宿主應用
- 19.3 通過嵌入包裝重新創建cli
- 19.4 老技術新用
- 19.5 小結
- 20 高級嵌入式
- 20.1 回調到php中
- 20.2 錯誤處理
- 20.3 初始化php
- 20.4 覆寫INI_SYSTEM和INI_PERDIR選項
- 20.5 捕獲輸出
- 20.6 同時擴展和嵌入
- 20.7 小結