首页 » Web前端 » php常驻内存变量技巧_PHP7变量的内部实现

php常驻内存变量技巧_PHP7变量的内部实现

duote123 2024-11-08 0

扫一扫用手机浏览

文章目录 [+]

变量的根本构造

//zend_types.htypedef 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:

php常驻内存变量技巧_PHP7变量的内部实现

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

php常驻内存变量技巧_PHP7变量的内部实现
(图片来自网络侵删)

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中的引用只可能有一层 ,不会涌现一个引用指向其余一个引用的情形 。

标签:

相关文章

2022跨年烟花璀璨星空下的光影盛宴

我国各地纷纷上演了一场场精彩纷呈的跨年烟花表演。璀璨的烟花在夜空中绽放,犹如璀璨星空下的光影盛宴,吸引了无数市民驻足观赏。在这辞旧...

Web前端 2025-03-02 阅读0 评论0

房山第一探寻历史文化名区的魅力与发展

房山区,位于北京市西南部,历史悠久,文化底蕴深厚。作为北京市的一个重要组成部分,房山区的发展始终与首都的发展紧密相连。房山区积极推...

Web前端 2025-02-18 阅读1 评论0

手机话费开钻代码数字时代的便捷生活

我们的生活越来越离不开手机。手机话费作为手机使用过程中的重要组成部分,其充值方式也在不断创新。手机话费开钻代码应运而生,为用户提供...

Web前端 2025-02-18 阅读1 评论0

探寻专业奥秘如何查询自己专业的代码

计算机科学已成为当今社会不可或缺的一部分。掌握一门专业代码对于个人发展具有重要意义。面对繁杂的学科体系,如何查询自己专业的代码成为...

Web前端 2025-02-18 阅读1 评论0