### 變量的內部實現
- 變量有兩個組成部分,變量名(zval),變量值(zend_value)。變量之間的傳遞,賦值通常也是針對zend_value操作的。
### zval 的基礎結構
```
typedef struct _zval_struct zval;
struct _zval_struct {
zend_value value;
u1;
u2;
}
// value保存具有變量類型的值或指針。
// value的結構
typedef union _zend_value {
zend_long lval; // int 整型(值)
double dval; // 浮點型(值)
zend_string *str; // string字符串型(指針)
zend_array *arr; // array數組(指針)
zend_object *obj; // object對象(指針)
zend_resource *res; // resource資源(指針)
zend_reference *ref; // 引用類型(指針)
...
} value;
// u1 的結構
union {
struct {
zend_uchar type, // 變量類型;若變量是true,false,null,則type直接表示值。其他類型則通過u1.type和value作對應,找到變量的值
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved
} v;
uint32_t type_info;
} u1;
// u2的結構
union {
uint32_t var_flags;
uint32_t next; //哈希表中解決哈希沖突時用到
uint32_t cache_slot;
uint32_t lineno;
uint32_t num_args;
uint32_t fe_pos;
uint32_t fe_iter_idx;
} u2
```
### zend_value 的結構
- 整型和浮點型
在變量賦值時,是直接復制
```
$a = 10
$b = $a 直接把$a所指向的zval復制一份給$b
```
- zend_string 字符串
二進制安全的,通過len變量來實現
```
// zend_string的結構
struct _zend_string {
zend_refcounted_h gc; // 變量引用信息
zend_ulong h; // 哈希值,數組中計算索引時會用到
size_t len; // 字符串長度,通過這個值保證了二進制安全
char val[1] // 字符串內容
}
// zend_string 寫時復制
$a = 'string'.date('Y-m-d');
$b = $a; // 當把$a賦值給$b時,其實在內存中$b 和 $a 都是指向同一個zend_string
$b = 'hello' // 當$b重新賦值時,這時候發生變化(寫時復制).將zend_string復制一份,
// 變成兩個zend_string.分別$a指向一個,$b指向一個。$b重新賦值時,只改變
// $b指向的zend_string,并不影響$a.
```
- zend_reference引用
引用是PHP中比較特殊的一種類型,它實際是指向另外一個PHP變量,對它的修改會直接改動實際指向的zval,可以簡單的理解為C中的指針,在PHP中通過`&`操作符產生一個引用變量,也就是說不管以前的類型是什么,`&`首先會創建一個`zend_reference`結構,其內嵌了一個zval,這個zval的value指向原來zval的value(如果是布爾、整形、浮點則直接復制原來的值),然后將原zval的類型修改為IS\_REFERENCE,原zval的value指向新創建的`zend_reference`結構。
```
struct _zend_reference {
zend_refcounted gc;
zval val;
}
舉例1
$a = "time:" . time(); //$a -> zend_string.gc.refcount=1
$b = &$a; //$a,$b -> zend_reference.gc.refcount=2 -> zend_string.gc.refcount=1
舉例2
$a = "time:" . time(); //$a -> zend_string.gc.refcount=1
$b = &$a; //$a,$b -> zend_reference.gc.refcount=2 -> zend_string.gc.refcount=1
$c = $b; //$a,$b -> zend_reference.gc.refcount=2 -> zend_string.gc.refcount=2
//$c->---------------------------------------------------?
//`$b = &$a`這時候`$a`、`$b`的類型是引用,但是`$c = $b`并不會直接將`$b`賦值給`$c`,而是把`$b`實際指向的zval賦值給`$c`
舉例3
$a = "time:" . time(); //$a -> zend_string.gc.refcount=1
$b = &$a; //$a,$b -> zend_reference.gc.refcount=2 -> zend_string.gc.refcount=1
$c = &$b;/*或$c = &$a*/ //$a,$b,$c -> zend_reference.gc.refcount=3 -> zend_string.gc.refcount=1
```
- zend_array數組
詳細介紹:http://www.hmoore.net/nickbai/php7/363268
```
// zend_array 的內部結構
struct _zend_array{
zend_refcounted gc; // gc 用于記錄引用信息
union {
...
} u;
uint32_t nTableMask; // 數組的key做hash運算后和nTableMask做與運算,計算出的值就是就是bucket負數索引的位置
Bucket *arData; // 數組中 key-value存儲的地方
uint32_t nNumUsed; // 占用的bucket的個數
uint32_t nNumOfElements;// 實際用到的bucket的個數
uint32_t nTableSize; // 數組的大小
uint32_t nInternalPointer;
zend_long nNextFreeElement; // 下一個無key 插入時,默認的key
}
// Bucket 的結構
typedef struct _Bucket {
zval val; // 數組value的zval
zend_long h; // key做hash運算后的值
zend_string *key // 數組的key
} Bucket
```
- linux 基礎
- ln 鏈接
- linux 環境變量
- linux 進程查看
- nginx
- redis
- redis 安裝
- php 底層原理
- php源碼編譯安裝
- phpize文件
- php命令行
- php7 新特性
- php7 變量
- php7 生命周期
- php sapi運行模式
- php 內存管理
- php 運行機制和Zend虛擬機
- php垃圾回收
- php 基礎
- php.ini
- php函數
- 面向對象
- php 文件上傳
- ob緩沖和頁面靜態化
- php中的session
- php cURL擴展
- composer 應用
- php 錯誤和異常
- thinkphp
- tp6容器和依賴注入
- tp6 的服務
- tp6事件
- tp6 多應用
- tp6路由
- tp6 cache
- tp6 request
- tp6 中間件
- tp6 response
- tp6 Db
- 備忘錄
- 數據庫表