本篇文章的內容介紹的是關於PHP7核心剖析7之Zend引擎執行過程 ,現在分享給大家,有需要的朋友可以參考一下
1.EG(executor_globals/zend_executor_globals)
PHP整個生命週期中最主要的一個結構,是一個全域變數,在main執行前分配(非ZTS下),直到PHP退出,它記錄著當前請求全部的資訊
2.EX(execute_data/zend_execute_data)
在執行過程中最核心的一個結構,每次函數的調用、include/require、eval等都會產生一個新的結構,它表示當前的範圍、代碼的執行位置以及局部變數的分配等等,
#define EX(element) ((execute_data)->element)struct _zend_execute_data { const zend_op *opline; //指向當前執行的opcode,初始時指向zend_op_array起始位置 zend_execute_data *call; /* current call */ zval *return_value; //傳回值指標 zend_function *func; //當前執行的函數(非函數調用時為空白) zval This; //這個值並不僅僅是物件導向的this,還有另外兩個值也通過這個記錄:call_info + num_args,分別存在zval.u1.reserved、zval.u2.num_args zend_class_entry *called_scope; //當前call的類 zend_execute_data *prev_execute_data; //函數調用時指向調用位置作用空間 zend_array *symbol_table; //全域變數符號表#if ZEND_EX_USE_RUN_TIME_CACHE void **run_time_cache; /* cache op_array->run_time_cache */#endif#if ZEND_EX_USE_LITERALS zval *literals; //字面量數組,與func.op_array->literals相同#endif};
3.Zend的執行流程
在Zend VM中zend_execute_data的zend_execute_data.opline,zend_execute_data.prev_execute_data,實現了call/ret
step1: 為當前範圍分配一塊記憶體,充當運行棧,zend_execute_data結構、所有局部變數、中間變數等等都在此記憶體上分配step2: 初始化全域變數符號表,然後將全域執行位置指標EG(current_execute_data)指向step1新分配的zend_execute_data,然後將zend_execute_data.opline指向op_array的起始位置step3: 從EX(opline)開始調用各opcode的C處理handler(即_zend_op.handler),每執行完一條opcode將EX(opline)++繼續執行下一條,直到執行完全部opcode,函數/類成員方法調用、if的執行過程:step3.1: if語句將根據條件的成立與否決定EX(opline) + offset所加的位移量,實現跳轉step3.2: 如果是函數調用,則首先從EG(function_table)中根據function_name取出此function對應的編譯完成的zend_op_array,然後像step1一樣新分配一個zend_execute_data結構,將EG(current_execute_data)賦值給新結構的prev_execute_data,再將EG(current_execute_data)指向新的zend_execute_data,最後從新的zend_execute_data.opline開始執行,切換到函數內部,函數執行完以後將EG(current_execute_data)重新指向EX(prev_execute_data),釋放分配的運行棧,銷毀局部變數,繼續從原來函數調用的位置執行step4: 全部opcode執行完成後將step1分配的記憶體釋放,這個過程會將所有的局部變數"銷毀",執行階段結束
4.運行時緩衝
在執行期間,PHP經常需要根據名稱去不同的雜湊表中尋找常量、函數、類、成員方法、成員屬性等,因此PHP提供了一種緩衝機制用於緩衝根據名稱尋找到的結果,以便再次執行同一opcode時直接複用上次緩衝的值,無需重複尋找,從而提高執行效率。運行時緩衝機制是在同一opcode執行多次的情況下才會生效,特別注意這裡的同一opcode指的並不是opcode值相同,而是指記憶體裡的同一份資料
實際上運行時緩衝是基於所屬opcode中CONST運算元儲存的,也就是說只有包含IS_CONST類型的運算元才有可能用到此機制,其它類型都不會用到,這是因為只有CONST運算元是固定不變的,其它CV、VAR等類型值都不是固定的,既然其值是不固定的那麼緩衝的值也就不是固定的,所以不會針對CONST以外類型的opcode操作進行緩衝
相關推薦:
PHP7核心剖析6之函數
PHP7核心剖析5之 PHP代碼的編譯
PHP7核心剖析4之局部變數,全域變數,常量