通過前面章節的描述,我們已經知道了PHP中變量的存儲方式--所有的變量都保存在zval結構中。下面介紹一下PHP內核如何實現變量的定義方式以及作用域。
## 變量的生命周期[]()
在ZE進行詞法和語法的分析之后,生成具體的opcode,這些opcode最終被execute函數(Zend/zend_vm_execute.h:46)解釋執行。在excute函數中,有以下代碼:
while (1) {
?
...
if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0) {
switch (ret) {
case 1:
EG(in_execution) = original_in_execution;
return;
case 2:
op_array = EG(active_op_array);
goto zend_vm_enter;
case 3:
execute_data = EG(current_execute_data);
default:
break;
}
}
...
}
這里的EX(opline)->handler(...)將op_array中的操作順序執行,其中變量賦值操作在ZEND_ASSIGN_SPEC_CV_CONST_HANDLER()函數中進行。ZEND_ASSIGN_SPEC_CV_CONST_HANDLER中進行一些變量類型的判斷并在內存中分配一個zval,然后將變量的值存儲其中。變量名和指向這個zval的指針,則會存儲于符號表內。ZEND_ASSIGN_SPEC_CV_CONST_HANDLER的最后會調用ZEND_VM_NEXT_OPCODE()將op_array的指針移到下一條opline,這樣就會形成循環執行的效果。
在ZE執行的過程中,有四個全局的變量,這些變量都是用于ZE運行時所需信息的存儲:
//_zend_compiler_globals 編譯時信息,包括函數表等
zend_compiler_globals *compiler_globals;
//_zend_executor_globals 執行時信息
zend_executor_globals *executor_globals;
//_php_core_globals 主要存儲php.ini內的信息
php_core_globals *core_globals;
//_sapi_globals_struct SAPI的信息
sapi_globals_struct *sapi_globals;
在執行的過程中,變量名及指針主要存儲于_zend_executor_globals的符號表中,_zend_executor_globals的結構這樣的:
struct _zend_executor_globals {
...
/* symbol table cache */
HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
HashTable **symtable_cache_limit;
HashTable **symtable_cache_ptr;
?
zend_op **opline_ptr;
?
HashTable *active_symbol_table; /* active symbol table */
HashTable symbol_table; /* main symbol table */
?
HashTable included_files; /* files already included */
...
?
}
在執行的過程中,active_symbol_table會根據執行的具體語句不斷發生變化(詳請見本節下半部分),針對線程安全的EG宏就是用來取此變量中的值。ZE將op_array執行完畢以后,HashTable會被FREE_HASHTABLE()釋放掉。 如果程序使用了unset語句來主動消毀變量,則會調用ZEND_UNSET_VAR_SPEC_CV_HANDLER來將變量銷毀,回收內存,這部分內存可以參考《第六章 內存管理》的內容。
- 第一章 準備工作和背景知識
- 第一節 環境搭建
- 第二節 源碼結構、閱讀代碼方法
- 第三節 常用代碼
- 第四節 小結
- 第二章 用戶代碼的執行
- 第一節 生命周期和Zend引擎
- 第二節 SAPI概述
- Apache模塊
- 嵌入式
- FastCGI
- 第三節 PHP腳本的執行
- 詞法分析和語法分析
- opcode
- opcode處理函數查找
- 第四節 小結
- 第三章 變量及數據類型
- 第一節 變量的結構和類型
- 哈希表(HashTable)
- PHP的哈希表實現
- 鏈表簡介
- 第二節 常量
- 第三節 預定義變量
- 第四節 靜態變量
- 第五節 類型提示的實現
- 第六節 變量的生命周期
- 變量的賦值和銷毀
- 變量的作用域
- global語句
- 第七節 數據類型轉換
- 第八節 小結
- 第四章 函數的實現
- 第一節 函數的內部結構
- 函數的內部結構
- 函數間的轉換
- 第二節 函數的定義,傳參及返回值
- 函數的定義
- 函數的參數
- 函數的返回值
- 第三節 函數的調用和執行
- 第四節 匿名函數及閉包
- 第五節 小結
- 第五章 類和面向對象
- 第一節 類的結構和實現
- 第二節 類的成員變量及方法
- 第三節 訪問控制的實現
- 第四節 類的繼承,多態及抽象類
- 第五節 魔術方法,延遲綁定及靜態成員
- 第六節 PHP保留類及特殊類
- 第七節 對象
- 第八節 命名空間
- 第九節 標準類
- 第十節 小結
- 第六章 內存管理
- 第一節 內存管理概述
- 第二節 PHP中的內存管理
- 第三節 內存使用:申請和銷毀
- 第四節 垃圾回收
- 新的垃圾回收
- 第五節 內存管理中的緩存
- 第六節 寫時復制(Copy On Write)
- 第七節 內存泄漏
- 第八節 小結
- 第七章 Zend虛擬機
- 第一節 Zend虛擬機概述
- 第二節 語法的實現
- 詞法解析
- 語法分析
- 實現自己的語法
- 第三節 中間代碼的執行
- 第四節 PHP代碼的加密解密
- 第五節 小結
- 第八章 線程安全
- 第二節 線程,進程和并發
- 第三節 PHP中的線程安全
- 第九章 錯誤和異常處理
- 第十章 輸出緩沖
- 第十六章 PHP語言特性的實現
- 第一節 循環語句
- foreach的實現
- 第二十章 怎么樣系列(how to)
- 附錄
- 附錄A PHP及Zend API
- 附錄B PHP的歷史
- 附錄C VLD擴展使用指南
- 附錄D 怎樣為PHP貢獻
- 附錄E phpt測試文件說明
- 附錄F PHP5.4新功能升級解析
- 附錄G:re2c中文手冊