這篇文章,研究一下PHP程式碼是如何解釋和執行以及PHP腳本運行的生命週期。
概述
PHP服務的啟動。嚴格來說,PHP的相關進程是不需要手動啟動的,它是隨著Apache的啟動而運作的。當然,如果有需要重啟PHP服務的情況下也是可以手動重啟PHP服務的。比如說在有開啟opcode的正式環境更新了程式碼之後,就需要重新啟動PHP才能重新編譯PHP程式碼。
從宏觀來看,PHP內核的實現就是接收輸入的數據,內部做相應的處理然後輸出結果。對PHP核心來說,我們寫的PHP程式碼就是核心接收的輸入數據,PHP核心接收程式碼資料後,對我們寫的程式碼進行程式碼解析和運算執行,最後回傳對應的運算結果。
然而,不同於平常的C語言程式碼,要執行PHP程式碼,首先需要將PHP程式碼「翻譯」成機器語言來執行對應的功能。而要執行「翻譯」這個步驟,就需要PHP核心進行:詞法分析、文法分析等步驟。最後交給PHP內核的Zend Engine進行順次的執行。
詞法分析
將PHP代碼分隔成一個個的「單元」(TOKEN)
語法分析
將「單元」轉換為Zend Engine可執行的操作
Zend Engine
對語法分析得到的操作順次的執行
一切PHP程式(CGI/CLI)的開始都是從SAPI(Server Application Programming Interface)介面開始。 SAPI指的是PHP具體應用的程式介面。例如Apache的mod_php。
PHP開始執行以後會經過兩個主要的階段:處理請求之前的開始階段和請求之後的結束階段。
開始階段
PHP的整個開始階段會經歷模組初始化和模組激活兩個階段。
MINIT
即模組初始化階段,發生在Apache/Nginx啟動以後的整個生命週期或命令列程式整個執行過程中,此階段只進行一次
RINIT
模組激活,發生在請求階段。做一些初始化工作:如註冊常數、定義模組使用的類別等等
模組在實作時可以透過如下巨集來實現這些回呼函數:
PHP_MINIT_FUNCTION(myphpextension) { //注册常量或者类等初始化操作 return SUCCESS; } PHP_RINIT_FUNCTION(myphpextension) { //例如记录请求开始时间 //随后在请求结束的时候记录结束时间。这样我们就能够记录处理请求所花费时间了 return SUCCESS; }
PHP腳本請求處理完就進入了結束階段,一般腳本執行到結尾或呼叫exit或die函數,PHP就進入結束階段。
結束階段
PHP的結束階段分為停用模組和關閉模組兩個環節。
RSHUTDOWN
停用模組(對應RINIT)
MSHUTDOWN
關閉模組(對應MINIT)
CLI/CGI模式的PHP屬於單一進程的SAPI模式。意思是說,PHP腳本在執行一次之後就關閉掉,所有的變數和函數都不能繼續使用。即在CGI模式下,同一個php檔案的變數在其他php檔案中不能使用。
下面用一個例子來看看單執行緒PHP的SAPI生命週期。
單執行緒SAPI生命週期
如:
php -f test.php
呼叫各個擴充的MINIT 模組初始化
請求test.php
》 test. 呼叫各個擴充的RSHUTDOWN 停用模組
執行完test.php後清理變數和記憶體
呼叫各個擴充的MSHUTDOWN 關閉模組
停止PHP執行
以上是一個簡單的執行流程,下面做一些補充。
PHP在呼叫每個模組的模組初始化前,會有一個初始化的過程,包括:
初始化若干全域變數 大多數情況下是將其設為NULL。
初始化若干常數
初始化Zend引擎和核心元件
解析php.ini
全域操作函數的初始化
初始化靜態建置的模組和共用模組(MINIT)
模組初始化執行操作:
將模組註冊到已註冊模組列表
將每個模組中包含的函數註冊到函數表
禁用函數和類別
會呼叫zend_disable_function函數將PHP的配置文件中的disable_functionsable_functions變數代表的函數從CG(function_table)函數表中刪除。
啟動Zend引擎
使用init_compiler函數來初始化編譯器。啟動SAPI
使用sapi_activate函數來初始化SG(sapi_headers)和SG(request_info),並且針對HTTP請求的方法設定一些內容。
環境初始化
初始化在使用者控制項需要用到的一些環境變數。包括伺服器環境、請求資料環境等。
模組請求初始化
PHP呼叫zend_activate_modules函數遍歷註冊在module_registry變數中的所有模組,呼叫其RINIT方法方法實現模組的請求初始化操作。
在處理了文件相關的內容後,PHP會呼叫php_request_startup做請求初始化操作:
啟動Zend引擎
啟動SAPI
環境初始化
模組請求初始化
DEACTIVATION(關閉請求)
以上就介紹了PHP是怎麼運作的,包括了方面的內容,希望對PHP教學有興趣的朋友有幫助。
呼叫所有透過register_shutdown_function()註冊的函數。這些在關閉時呼叫的函數是在用戶空間添加進來的。
執行所有可用的__destruct函數。這裡的析構函數包括在物件池(EG(objects_store)中的所有物件的析構函數以及EG(symbol_table)中各個元素的析構方法。
將所有的輸出刷出去。
發送HTTP應答頭。
銷毀全域變數表(PG(http_globals))的變數。
透過zend_deactivate函數,關閉詞法分析器、語法分析器和中間程式碼執行器。函數指標都是NULL。
結束
PHP結束一個進程是,會呼叫sapi_flush函數將最後的內容刷新出去。 (http://www.php-internals.com/book/)