PHP的內核子系統有兩個,ZE(Zend Engine)和PHP Core.
ZE負責將PHP腳本解析成機器碼(也成為token符)後,在進程空間執行這些機器碼;ZE還負責內存管理,變量作用域管理和對PHP函數的調度管理。
PHP Core負責和SAPI層的通信;PHP Core也為safe_mode, open_basedir的檢查提供了統一控制層;PHP Core還提供了streams層,用於用戶域的文件和網絡IO操作。其中SAPI(Server Application Programming Interface)通常包含Nginx,Apache,IIS,CLI,CGI等主機環境。
PHP擴展在ZE和PHP Core的基礎上提供對各種常用操作的封裝,比如對mysql,redis,memcache,sqlite等的讀寫,對json,xml文件的解析,對soap,sokcet,curl的網絡協議的封裝,對加密解密壓縮解壓縮等的封裝,對圖像處理的封裝等等。有些擴展是從零開始實現某個功能,比如按照redis的通信協議使用C來實現和redis的通信;有些擴展則是通過調用系統已有的庫,比如圖片處理的gb擴展需要系統本身要安裝了相應的gd庫。
在PHP源碼php-5.6.24/ext中提供了78個擴展。
總之,由ZE和PHP Core提供基礎的架構,由EXT(擴展)提供用戶域的各種操作。
以php-5.6.24源碼為例,ZE對應文件夾php-5.6.24/Zend, PHP Core對應文件夾php-5.6.24/main, 擴展對應文件夾php-5.6.24/ext。
PHP在接收到SAPI命令時,首先初始化並啟動它的內核子系統,在內核子系統的啟動快結束時,PHP開始加載它的擴展代碼並對擴展初始化,此時PHP將調用每個模塊的初始化例程Module Initialization routine (MINIT)。
MINIT(Module Initialization)
PHP調用MINIT相關例程,使得每個擴展有機會初始化內部變量、分配資源、注冊資源處理句柄,以及向ZE注冊自己的函數,以便於腳本調用這其中的函數時候ZE知道執行哪些代碼
RINIT(Request Initialization)
在模塊初始化完成後,PHP等待來自SAPI的請求,當接收到SAPI請求後,由ZE為當前被請求的php腳本創建運行環境,並調用每個擴展的Request Initialization(RINIT)函數,使得每個擴展有機會設定特定的環境變量,根據請求分配資源,或者執行其他任務,如審核。
這裡所說的SAPI請求分為兩類,一類是Apache, IIS, 和其他成熟的web server SAPIs,他們在啟動時PHP先執行了MINIT,之後等待來自用戶的頁面請求,當收到請求後執行RINIT;另一類SAPI請求則是CGI or CLI SAPIs,PHP在收到這類SAPI請求時,執行完MINIT馬上就執行RINIT。
當RINIT請求初始化完畢後,ZE接回控制權並將當前被請求的腳本翻譯成tokens, 最終構成opcodes(操作碼),opcodes被執行過程中,如果某個opcode要求執行某個擴展函數,這是ZE就會將相關參數綁定到改函數,並將控制權臨時交給該函數去執行,直到該函數執行完畢。
RSHUTDOWN(Request Shutdown)
PHP腳本運行結束後,PHP調用每個擴展的請求關閉(RSHUTDOWN)函數以執行最後的清理工作(如將session變量存入磁盤)。接下來,ZE執行清理過程(垃圾收集),有效地對之前的請求期間用到的每個變量執行unset()。
MSHUTDOWN(Module Shutdown)
當RSHUTDOWN完成後,PHP繼續等待SAPI的其他文檔請求或者是關閉信號。對於CGI和CLI等SAPI,沒有“下一個請求”,所以SAPI立刻開始關閉。關閉期間,PHP再次遍歷每個擴展,調用其模塊關閉(MSHUTDOWN)函數,並最終關閉自己的內核子系統。
GINIT
初始化全局變量
GSHUTDOWN
釋放全局變量
MINFO
設置phpinfo模塊的信息,phpinfo要等級每個擴展的配置信息
// main/php.h #define PHP_MINIT ZEND_MODULE_STARTUP_N #define PHP_MSHUTDOWN ZEND_MODULE_SHUTDOWN_N #define PHP_RINIT ZEND_MODULE_ACTIVATE_N #define PHP_RSHUTDOWN ZEND_MODULE_DEACTIVATE_N #define PHP_MINFO ZEND_MODULE_INFO_N #define PHP_GINIT ZEND_GINIT #define PHP_GSHUTDOWN ZEND_GSHUTDOWN #define PHP_MINIT_FUNCTION ZEND_MODULE_STARTUP_D #define PHP_MSHUTDOWN_FUNCTION ZEND_MODULE_SHUTDOWN_D #define PHP_RINIT_FUNCTION ZEND_MODULE_ACTIVATE_D #define PHP_RSHUTDOWN_FUNCTION ZEND_MODULE_DEACTIVATE_D #define PHP_MINFO_FUNCTION ZEND_MODULE_INFO_D #define PHP_GINIT_FUNCTION ZEND_GINIT_FUNCTION #define PHP_GSHUTDOWN_FUNCTION ZEND_GSHUTDOWN_FUNCTION
ZE在執行自己內部的內存管理時,通過附加的標志來標識某某內存變量是否是持久性的,對於非持久內存,ZE會去清理。但在擴展內部最好還是自己去清理非持久內存,因為擴展自己請求分配的非持久內存,將在長時間內保持為未回收狀態,這樣與之相關的資源長時間得不到釋放。
參考文章:Extension Writing Part I: Introduction to PHP and Zend