PHP源码分析(基本变量)
作者:互联网
小而巧的zval
zval可以表示PHP中任意一个变量
struct_zval_struct{
zend_value value;
union u1;
union u2;
}
typedef union_zend_value{
zend_long lval; //整形
double dval; //浮点型
zend_refcounted *counted
zend_string *str; //字符串
zend_array *arr; //数组 ->hashtable
zend_object *obj; //对象
zend_resource *res; //资源类型
zend_reference *ref; //引用类型
zend_ast_ref *ast; //抽象语法树
zval *zv; //还可以指向一个zval
void *ptr; //不确定类型
zend_class_entry *ce;//类
zend_function *func;
}zend_value;
源码图:文件zand_types.h
u1: type 定义了不同的类型
type_flags 是变量类型特有的标记,可以表示常量、不可变的类型、需要引入计数的类型、可能包括循环引用的类型、可被复制的类型
const_flags:是常量类型特有的标记,0变量 2常量
reserved 是保留字段
u2:next 是主要解决hash冲突的
cache_slot 主要是做运行时缓存的
lineno 标记了哪一行,一般用作AST抽象语法树
num_args:代表函数调用输入参数的个数
fe_pos:代表我们foreach的时候位置,每foreach一次这个值+1
fe_iter_idx:也在foreach中使用,代表游标索引的位置
access_flags:主要用在类里面比如写代码用到的public、protected等
property_guard:防止类中魔术方法的循环引用,在get和set中会用到
其中zval里面有三个变量,他们都是联合体, value里面有各种类型的指针,它的类型判断是由u1里面的type来判断的,根据type来取里面不同的值,比如type里面是IS_LONG整形,可以直接取zend_value里面的lval,就得到值了,如果type是string,我们取*str,它是一个指向zend_string的指针
变量都挨在一起放在同一段内存中,每一个都占了16字节
从源码中我们看到虽然说PHP是弱语言类型,但是在真正的底层实现还是区分类型的,为什么需要区分类型呢?
如果知道一个变量想知道它的长度的话有这么几种方法,一个是专门用一个长度的字段来记录长度比如我们字符串,数组的话我们有一个长度的字段,其他的我们用类型这个字段,而类型天然有长度这个字段,一个类型隐世的包含它的长度,比如我们定义 $a=1虽然我们没有定义类型,但是底层解析会把他定义为整形,会用到zend_value 的lval
如何区分类型:看u1里面的结构体v的type,这个type就是代表不同的类型,类型定义了有IS_FALSE、IS_TRUE、IS_LONG、IS_ARRAY、IS_OBJECT等,另外还有一个type_info,可以快速的取出上面的四个char的值
Zend_string 字符串
gc对应一个结构体,主要是进行垃圾回收的,refcount为引用计数
h 为这个字符串对应的hash值,后面会用在数组里面
len和val[1]:是二进制安全的,不像c语言中如果/0就会被截断,两个就可以表示一个字符串,其中gc和h主要用作垃圾回收和以空间换时间做hash运算时存储的一个h值
写时复制:如果是整形或者其他简单的类型,用zval的16个字节就可以表示,所以是直接赋值的,比如zend_string,$a='string',$b=$a,他们的*str指向同一个zend_string,使用gc里面的refcount+1,当修改b的时候进行copy一份出来进行修改
对于7.1.0的话 refcount=0,flags=2常量 变量的话 refcount=1,flags=0,并且字符串是写时复制的,当没有修改前的话,他们的*str都指向同一个zend_string,修改后refcount-1,并且分配一个新的地址
引用类型:
在zend_value里面
zend_reference *ref 对应 IS_REFERENCE
当把$b=&$a的的时候,a的type也变成10,引用类型了,都是同一个地址
当$a复制string的时候,$a对应的zval的类型为IS_STRING,指向的是zend_string,当$b=&$a的时候,它们的类型都变成了zend_reference,它们指向同一个zend_reference,zend_reference里面有zval,它的类型为IS_STRING,指向zend_string。 当使用unset($b)时候,只是把b的zval的type类型改为NULL,甚至ref地址的指针都没有变,而a的zval的type还是为10,类型为ref没有变,指向的zend_string也没有变
Zend_array 数组
zend_array 还有个别名 HashTable
TableMask:计算索引值
*arDate:真正存储的是key-value对
NumUsed:已经用过的空间
TableSize:代表的是arDate的大小,初始化的话大小为8,当不够用的话进行扩容8-16-32
NextFreeElement:当我们直接赋值没有key的value
整个HashTable分为了Bucket arr和hash arr
Bucket array是后面存arrData的下标一个个往上加的,0123,我写进去的时候他们key一定是数字,这个arData前面有一个索引的数组,只用两个位置,分别是-1和-2,这个是Bucke array
Hash array是算出来的hash值& nTableMask得到一个值
标签:string,zend,value,源码,类型,zval,PHP,type,变量 来源: https://blog.csdn.net/ligupeng7929/article/details/90041631