php 结构体_PHP底层原理知其然知其所以然
1·、PHP變量的底層實現
PHP代碼執行圖解
1.1:變量在內存中的存儲結構
PHP變量是通過zval結構體來存儲的,文件: Zend/zend.h 316行左右
1.2:值的存儲
PHP變量的值是放在zval結構體中的value段中的,文件: Zend/zend.h
1.3:結構體的字段解釋
struct _zval_struct {
/* Variable information */
zvalue_value value; /*變量的值,是個聯合體*/
zend_uint refcount__gc; /*指向次數*/
zend_uchar type; /* 變量類型 */
zend_uchar is_ref__gc; /*是否引用*/
};
type字段的值為以下常量
IS_NULL, IS_BOOL,IS_LONG,IS_DOUBLE
IS_STRING,IS_ARRAY,IS_OBJECT
IS_RESOURCE
1.4:聯合體中的值
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;
聯合中為什么只列出了5種值?
NULL不用,zval的type為IS_NULL即可
Bool以1,0存儲在lval上
resource的type為resource,其resource的內容用long來標志(資源標記)
1.5:變量的結構圖
1.6:變量的創建
創建變量的步驟: $str = "hello";
1:創建zval結構,并設置其類型 IS_STRING
2:設置其值為 hello
3:講其加入符號表?
{
? ? zval *fooval;
? ? MAKE_STD_ZVAL(fooval);
? ? ZVAL_STRING(fooval, "hello", 1);
? ? ZEND_SET_SYMBOL( EG(active_symbol_table) ,? "foo" , fooval);
}
1.7:符號表 symbol_table
符號表是什么?
符號表是一張哈希表,里面存儲了變量名->變量的zval結構體的地址,
// zend/zend_globals.h 182行
struct _zend_executor_globals {
? ? ...
? ? ...
HashTable *active_symbol_table; /*活動符號表*/
HashTable symbol_table; /* 全局符號表 */
HashTable included_files; /* files already included */
1.8:符號表與函數
Zend/zend_compiles.h
struct _zend_execute_data {
? ? ...
? ? zend_op_array *op_array; //函數的執行步驟
? ? HashTable *symbol_table; // 此函數的符號表地址
? ? zend_class_entry *current_scope;
? ? zval *current_this;
? ? zval *current_object;
? ? ...
};
上面這個,是當前函數執行時的符號表
1.9:符號表與作用域
當執行到函數時,會生成函數的"執行環境結構體",包含函數名,參數,執行步驟,所在的類(如果是方法),以及為這個函數生成一個符號表.符號表統一放在棧上.并把active_symbol_table指向剛產生的符號表
1.10:函數中靜態變量的實現
2.0:常量-常量結構體
結構體 Zend/constants.h 33行
typedef struct _zend_constant {
zval value;? //變量結構體
int flags;? ? //標志,是否大小寫敏感等
char *name; //常量名
uint name_len;
int module_number;//模塊名
} zend_constant;
2.1:常量的生成
int zend_register_constant(zend_constant *c TSRMLS_DC) {
...
...
zend_hash_add(EG(zend_constants), name, c->name_len, (void *) c, sizeof(zend_constant), NULL)==FAILURE)
...
...
}
2.2:define函數的實現
define函數當然是調用zend_register_constant聲明的常量 :)?
具體如下 Zend/zend_builtin_functions.c
關鍵代碼:
c.value = *val;
zval_copy_ctor(&c.value);
if (val_free) {
zval_ptr_dtor(&val_free);
}
c.flags = case_sensitive; /* non persistent */
c.name = zend_strndup(name, name_len);
c.name_len = name_len+1;
c.module_number = PHP_USER_CONSTANT;
if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
2.3:有趣的測試
1:常量并沒有檢測名字...
define('^_^',"laugh");
2:常量的第2個參數還可以是對象,與手冊上介紹的不同
define('obj',new className());
(當然,對象要有toString方法等著)
2.4:常量為什么是全局有效的?
很簡單,常量的哈希表只有一個
EG(zend_constants)
3.0:內存管理與垃圾回收
PHP封裝了對系統內存的請求,不要直接用malloc直接請求內存
3.1:PHP的hashtable太強大
3.2:引用計數
$a = 1;
$b = $a;
?>
$a,$b的值及類型 都一樣,有必要再申請一個zval結構嗎?
3.3:引用計數解釋
$a = 1;
$b = $a;
?>
當$a的值賦給$b時,并沒有為$b生成一個新的zval結構體.而是$b與$a共享一個結構體.
3.4:copy-on-write 寫時復制
$a = 1;
$b = $a;
$b=6
?>
3.5:引用傳值發生了什么?
$a = 1;
$b = &$a;
?>
3.6:引用傳值為什么影響了2個值
$a = 1;
$b = &$a;
$b = 6;
?>
內核修改zval的值時,發現is_ref_gc為1,則直接修改該value,而不是復制一份.如下圖:
總結
以上是生活随笔為你收集整理的php 结构体_PHP底层原理知其然知其所以然的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最近有好看的电影推荐吗?
- 下一篇: 求戳进