您的位置 首页 php

PHP7-变量的内部实现

变量的基础结构

//zend_types.h
typedef struct _zval_struct zval;
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;
struct _zval_struct {
 zend_value 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;
 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; //一些辅助值
};
 

zval结构比较简单,内嵌一个union类型的zend_value保存具体变量类型的值或指针,zval中还有两个union:u1、u2:

u1: 它的意义比较直观,变量的类型就通过u1.v.type区分,另外一个值type_flags为类型掩码,在变量的内存管理、gc机制中会用到(之前分享的垃圾回收机制中,变量的type_flags只有包含IS_TYPE_COLLECTABLE的变量才会被GC收集)

u2: 这个值纯粹是个辅助值,假如zval只有:value、u1两个值,整个zval的大小也会对齐到16byte,既然不管有没有u2大小都是16byte,把多余的4byte拿出来用于一些特殊用途还是很划算的,比如next在哈希表解决哈希冲突时会用到,还有fe_pos在foreach会用到……

从zend_value可以看出,除 long double 类型直接存储值外,其它类型都为指针,指向各自的结构。

类型

标量 类型

最简单的类型是true、 false 、long、double、null,其中true、false、null没有value,直接根据type区分,而long、double的值则直接存在value中:zend_long、double,也就是标量类型不需要额外的value指针。

字符串

PHP中字符串通过zend_string表示:

struct _zend_string {
 zend_refcounted_h gc;
 zend_ulong h; /* hash value */
 size_t len;
 char val[1];
};
 

gc: 变量引用信息,比如当前value的引用数,所有用到引用计数的变量类型都会有这个结构,3.1节会详细分析

h: 哈希值,数组中计算 索引 时会用到

len: 字符串长度,通过这个值保证二进制安全

val: 字符串内容,变长struct,分配时按len长度申请内存

数组

array是PHP中非常强大的一个数据结构,它的底层实现就是普通的有序 HashTable ,这里简单看下它的结构。

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 reserve)
 } 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;
};
对象/资源
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];
};
struct _zend_resource {
 zend_refcounted_h gc;
 int handle;
 int type;
 void *ptr;
};
 

引用

在PHP中通过&操作符产生一个引用变量,也就是说不管以前的类型是什么,&首先会创建一个zend_reference结构,其内嵌了一个zval,这个zval的value指向原来zval的value(如果是布尔、整形、浮点则直接复制原来的值),然后将原zval的类型修改为IS_REFERENCE,原zval的value指向新创建的zend_reference结构。

struct _zend_reference {
 zend_refcounted_h gc;
 zval val;
};
 

结构非常简单,除了公共部分zend_refcounted_h外只有一个val,举个示例看下具体的结构关系:

$a = "time:" . time(); //$a -> zend_string_1(refcount=1)
$b = &$a; //$a,$b -> zend_reference_1(refcount=2) -> zend_string_1(refcount=1)
 

最终的结果如图:

image.png

注意:引用只能通过&产生,无法通过赋值传递,比如:

$a = "time:" . time(); //$a -> zend_string_1(refcount=1)
$b = &$a; //$a,$b -> zend_reference_1(refcount=2) -> zend_string_1(refcount=1)
$c = $b; //$a,$b -> zend_reference_1(refcount=2) -> zend_string_1(refcount=2)
 //$c -> ---
 

b = &a这时候a、b的类型是引用,但是c = b并不会直接将b赋值给c,而是把b实际指向的zval赋值给c,如果想要$c也是一个引用则需要这么操作:

$a = "time:" . time(); //$a -> zend_string_1(refcount=1)
$b = &$a; //$a,$b -> zend_reference_1(refcount=2) -> zend_string_1(refcount=1)
$c = &$b;/*或$c = &$a*/ //$a,$b,$c -> zend_reference_1(refcount=3) -> zend_string_1(refcount=1) 
 

这个也表示PHP中的引用只可能有一层 ,不会出现一个引用指向另外一个引用的情况 。

文章来源:智云一二三科技

文章标题:PHP7-变量的内部实现

文章地址:https://www.zhihuclub.com/149420.shtml

关于作者: 智云科技

热门文章

网站地图