### 变量的内部实现
- 变量有两个组成部分,变量名(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数组
详细介绍:https://ihavenolimitations.xyz/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
- 备忘录
- 数据库表