變量名zval,變量值zend_value,如php腳本聲明一個變量時,會創建一個zval;對變量賦值是保存在zend_value上;
另外php7的引用計數是在zend_value,而不是zval
### zval結構:
```c
//zend_types.h
typedef struct _zval_struct zval; // zval是struct _zval_struct結構體的別名
struct _zval_struct {
zend_value value; // 變量實際的值
union {
struct {
ZEND_ENDIAN_LOHI_4( //這個是為了兼容大小字節序,小字節序就是下面的順序,大字節序則下面4個順序翻轉
zend_uchar type, //變量類型
zend_uchar type_flags, //類型掩碼,不同的類型會有不同的幾種屬性,內存管理會用到
zend_uchar const_flags,
zend_uchar reserved) //call info,zend執行流程會用到
} v;
uint32_t type_info; //上面4個值的組合值,可以直接根據type_info取到4個對應位置的值
} u1; // 通過zval.u1.type可知知道變量類型
union {
uint32_t var_flags;
uint32_t next; //哈希表中解決哈希沖突時用到
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
} u2; //一些輔助值
};
```
### zend_value結構:
```c
typedef union _zend_value {
zend_long lval; //int整形
double dval; //浮點型
zend_refcounted *counted;
zend_string *str; //string字符串
zend_array *arr; //array數組
zend_object *obj; //object對象
zend_resource *res; //resource資源類型
zend_reference *ref; //引用類型,通過&$var_name定義的
zend_ast_ref *ast; //下面幾個都是內核使用的value
zval *zv;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
```
由zend_value可以看到,類型zend_long和double是直接保存值,而其他類型是保存一個指向各自結構的指針,以下是各種類型的結構:
#### 字符串 zend_string
```c
struct _zend_string {
zend_refcounted_h gc;
zend_ulong h; /* hash value */
size_t len;
char val;
};
```
#### 數組 zend_array
```c
typedef struct _zend_array HashTable;
struct _zend_array {
zend_refcounted_h gc; //引用計數信息,與字符串相同
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar flags,
zend_uchar nApplyCount,
zend_uchar nIteratorsCount,
zend_uchar consistency)
} v;
uint32_t flags;
} u;
uint32_t nTableMask; //計算bucket索引時的掩碼
Bucket *arData; //bucket數組
uint32_t nNumUsed; //已用bucket數
uint32_t nNumOfElements; //已有元素數,nNumOfElements <= nNumUsed,因為刪除的并不是直接從arData中移除
uint32_t nTableSize; //數組的大小,為2^n
uint32_t nInternalPointer; //數值索引
zend_long nNextFreeElement;
dtor_func_t pDestructor;
};
```
數組使用哈希表(hashTable)來實現,哈希表即通過key-value訪問數據,這里的key是直接映射到內存地址,也就是說根據key可以直接獲得保存在內存的值(這種方式稱尋址技術);
數組的元素存在Bucket結構:
```c
//Bucket:散列表中存儲的元素
typedef struct _Bucket {
zval val; //存儲的具體value,這里嵌入了一個zval,而不是一個指針
zend_ulong h; //key根據times 33計算得到的哈希值,或者是數值索引編號
zend_string *key; //存儲元素的key
} Bucket;
```
#### 對象 zend_object
```c
struct _zend_object {
zend_refcounted_h gc;
uint32_t handle;
zend_class_entry *ce; //對象對應的class類
const zend_object_handlers *handlers;
HashTable *properties; //對象屬性哈希表
zval properties_table[1];
};
```
#### 資源 zend_resource
```c
struct _zend_resource {
zend_refcounted_h gc;
int handle;
int type;
void *ptr;
};
```
#### 引用 zend_reference
```c
struct _zend_reference {
zend_refcounted_h gc;
zval val;
};
```
&首先會創建一個zend_reference結構,其內嵌了一個zval,這個zval的value指向原來zval的value(如果是布爾、整形、浮點則直接復制原來的值),然后將原zval的類型修改為IS_REFERENCE,原zval的value指向新創建的zend_reference結構。

### 參考:
- 《PHP7內核剖析》
- 《PHP7底層設計和源碼分析》
#define ZVAL_DEREF(z) do { \
if (UNEXPECTED(Z_ISREF_P(z))) { \
(z) = Z_REFVAL_P(z); \
} \
} while (0)
do {
if (__builtin_expect(!!(z->u1.v.type == IS_REFERENCE), 0)) {
z = &((*z).value.ref->val)
}
}
- php
- 編譯安裝
- 基本概念
- 垃圾回收機制
- 生命周期
- zval底層實現
- c擴展開發
- gdb調試工具
- 自定義擴展簡單demo
- 鉤子函數
- 讀取php.ini配置
- 數組
- 函數
- 類
- yaf擴展底層源碼
- swoole擴展底層源碼
- memoryGlobal內存池
- swoole協程使用記錄
- 單點登錄sso原理
- compser使用
- session實現機制
- c & linux
- gcc
- 指針
- 結構體,聯合和位字段
- 宏定義井號說明
- printf家族函數和可變參數
- 共享函數
- 靜態庫和動態庫
- makefile自動化構建
- 信號一
- 信號二
- inotify監控文件事件
- socket編程
- 簡介
- UNIX DOMAIN
- Internet DOMAIN
- TCP/IP
- 文件IO多路復用
- 內存管理
- 進程組,會話和控制終端
- daemon守護進程
- 多進程
- 多線程
- 常用進制轉換
- go
- 入門知識
- 字節和整數裝換
- python
- redis
- 應用場景
- 消息隊列
- 熱點數據
- 掃碼登錄
- 訂閱發布
- 次數限制
- 搶購超賣
- 持久化機制
- mysql
- 工作流程
- MyISAM和InnoDB區別
- 用戶和權限管理
- 執行計劃
- sql優化
- 事務和鎖
- 慢查詢日志
- case...when...then...end用法
- sql
- 參考
- linux
- 內核參數優化
- 防火墻設置
- docker
- docker入門知識
- 算法
- 多維數組合
- DFA算法
- 紅包金額分配