1.SAPI
腳本執行的開始都是SAPI接口實現開始的。只是不同的SAPI接口實現會完成他們的特定工作,例如Apache的mod_php SAPI實現需要初始化從Apache獲取的一些信息,在輸出內容則是將內容返回給Apache。
2.開始和結束
PHP開始執行以后會經歷兩個主要階段:處理請求之前的開始階段和請求之后 結束階段。
開始階段:模塊初始化MINIT;第二個過程是RINIT請求開始。(如PHP注冊了一些擴展模塊,則在MINIT階段會回調所有模塊的MINIT函數),模塊在這個階段可以進行一些初始化工作,例如注冊常量、定義模塊使用類等。模塊在實現PHP_MINIT_FUNCTION(myphpextension){
注冊常量或者類等初始化工作
return SUCCESS;
}
請求到達之后PHP初始化腳本的執行環境,例如創建一個執行環境,包括保存PHP運行過程中變量名稱和值內容的符號表以及當前所以的函數以及類等信息的符號表,然后PHP會調用所以模塊的RINT函數,在這個階段各個模塊也可以執行一些相關操作,模塊的RINT函數和MINIT回調函數類似:PHP_RINT_FUNCTION(myphpextension){
//注冊常量或者類等初始化工作
//例如記錄請求開始時間
//隨后在請求結束的時候記錄結束時間,這樣就可以記錄處理請求所花費的時間
return SUCCESS;
}
請求處理完成就進入了結束階段,一般腳本執行到末尾或者通過調用exit或die函數。結束也分為2個環節,一個在請求結束后停用模塊(RSHUTDOWN,對應RINIT),一個在SAPI生命周期結束(web服務器退出或者命令行腳本執行完畢退出)時關閉模塊(MSHUTDOWN,對應MINIT)
整個SAPI類似於一個面向對象中的模板方法模式的應用。SAPI.c和SAPI.h文件所包含的一些函數就是模板方法中的抽象模板,各個服務器對於sapi_module的定義和相關實現是一個個具體模板;
php擴展中,每個擴展都需要定義一個zend_module_entry結構體,在PHP生命周期中,如果需要調用某個擴展,其調用的方法都是zend_module_entry結構中指定的方法;
Apache的php模塊
當php需要在Apache下運行時,一般來說是mod_php5模塊的形式集成的。接收apache傳遞來的php文件請求。如配置好模塊,php模塊通過注冊apache2的ap_hook_post_config掛鈎,在Apache啟動時候啟動此模塊以接受PHP文件請求。
Zend引擎詞法分析
變量類型
標量類型:boolean integer float string
復合類型:array object
特殊類型:resource NULL
1.變量存儲結構
變量的值存儲到以下所示zval結構體中。zval結構體定義在zend/zend.h文件;
php在存儲變量時將PHP用戶空間的變量類型也保存在同一個結構體中。
屬性名
含義
默認值
refcount_gc
表示引用計數
1
is_ref_gc
表示是否為引用
0
value
存儲變量的值
type
變量具體類型
php5.3之前是refcount和is_ref;
變量的值存儲在zvalue_value
2.變量類型
type字段就是實現弱類型最關鍵的字段。值為IS_NULL,IS_BOOL,IS_LONG,IS_DOUBLE,IS_STRING,IS_ARRAY,IS_OBJECT
,IS_RESOURCE。
3.變量值存儲typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
使用union是為了空間利用率的考慮。
數組的值存儲在zvalue_value.ht字段中,它是一個HashTable類型的數據。PHP使用哈希表來存儲關聯數據。哈希表是一種高效的鍵值對存儲結構,PHP哈希表實現中使用了兩個數據結構HashTable和Bucket。
對象Objecttypedef struct _zend_object_value {
zend_object_handle handle; // unsigned int類型,EG(objects_store).object_buckets的索引
zend_object_handlers *handlers;
} zend_object_value;
數據結構:
首先我們需要一個容器來保存我們的 哈希表,哈希表需要保存的內容主要是保存進來的數據,同時為了方便的得知哈希表中存儲的元素個數,需要保存一個大小字段。第二個就是需要保存數據的容器了。