分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 代码编程

跟厂长学PHP内核7(六):变量之zval

发布时间:2023-09-06 02:14责任编辑:苏小强关键词:PHP

记得网上流传甚广的段子“PHP是世界上最好的语言”,暂且不去讨论是否言过其实,但至少PHP确实有独特优势的,比如它的弱类型,即只需要$符号即可声明变量,使得PHP入手门槛极低,成为大家所青睐的Web服务端语言。那么它的变量是如何实现的呢?我们今天就来学习一下PHP的基本变量。

一、引言

PHP的变量存储在zval结构体中,在执行阶段中编译为op_array时就能看到zval的身影。结构体定义在Zend/zend_types.h中,定义内容如下所示:

struct _zval_struct { ???zend_value ???????value; ???????????/* value */ ???union { ???????struct { ???????????ZEND_ENDIAN_LOHI_4( ???????????????zend_uchar ???type, ????????/* active type */ ???????????????zend_uchar ???type_flags, ???????????????zend_uchar ???const_flags, ???????????????zend_uchar ???reserved) ????/* 保留字段 */ ???????} v; ???????uint32_t type_info; ???} u1; ???union { ???????uint32_t ????var_flags; ???????uint32_t ????next; ????????????????/* hash collision chain */ ???????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;};

二、结构体剖析

2.1、zend_value

结构体的第一个变量是zend_value,顾名思义,它其实也是一个结构体,用于存放变量的值,比如整型、浮点型、引用计数、字符串、数组、对象、资源等。zend_value定义了众多类型的指针,但这些类型并不都是变量的类型,有些是给内核自己使用的,比如指针ast、zv、ptr。

typedef union _zend_value { ???zend_long ????????lval; ????????????/* 整型 */ ???double ???????????dval; ????????????/* 浮点型 */ ???zend_refcounted ?*counted; ?????????/* 引用计数 */ ???zend_string ?????*str; ?????????????/* 字符串 */ ???zend_array ??????*arr; ?????????????/* 数组 */ ???zend_object ?????*obj; ?????????????/* 对象 */ ???zend_resource ???*res; ?????????????/* 资源 */ ???zend_reference ??*ref; ?????????????/* 引用 */ ???zend_ast_ref ????*ast; ?????????????/* 抽象语法树 */ ???zval ????????????*zv; ??????????????/* zval类型 */ ???void ????????????*ptr; ?????????????/* 指针类型 */ ???zend_class_entry *ce; ??????????????/* class类型 */ ???zend_function ???*func; ????????????/* function类型 */ ???struct { ???????uint32_t w1; ???????uint32_t w2; ???} ww;} zend_value;

2.2、u1

u1是一个联合体,它联合了结构体v和整型type_info。下面我们先来看一下结构体v的构成。

union { ???struct { ???????ZEND_ENDIAN_LOHI_4( ???????????zend_uchar ???type, ????????/* active type */ ???????????zend_uchar ???type_flags, ???????????zend_uchar ???const_flags, ???????????zend_uchar ???reserved) ????/* call info for EX(This) */ ???} v; ???uint32_t type_info;} u1;

2.2.1、type

type是指变量的类型,刚在2.1中讲到了zend_value是用来存储变量的值,所以也应该有地方存储变量的类型,而这就是type的职责。以下是PHP定义的所有变量类型,有我们熟知的布尔、NULL、浮点、数组、字符串等类型。也有陌生的undef、indirect、ptr类型,变量类型在下一章中详解,这里不再赘述。

/* regular data types */#define IS_UNDEF ???????????????????0#define IS_NULL ????????????????????1#define IS_FALSE ???????????????????2#define IS_TRUE ????????????????????3#define IS_LONG ????????????????????4#define IS_DOUBLE ??????????????????5#define IS_STRING ??????????????????6#define IS_ARRAY ???????????????????7#define IS_OBJECT ??????????????????8#define IS_RESOURCE ????????????????9#define IS_REFERENCE ???????????????10/* constant expressions */#define IS_CONSTANT ????????????????11#define IS_CONSTANT_AST ????????????12/* fake types */#define _IS_BOOL ???????????????????13#define IS_CALLABLE ????????????????14/* internal types */#define IS_INDIRECT ????????????????15#define IS_PTR ?????????????????????17

2.2.2、type_flags

可以把它理解为子类型,上面提到了变量的类型,这个是针对不同类型的子类型或标记,type_flags一共有以下6种。

/* zval.u1.v.type_flags */#define IS_TYPE_CONSTANT ???????????(1<<0) ?/* 常量 */#define IS_TYPE_IMMUTABLE ??????????(1<<1) ?/* 不可变的类型 */#define IS_TYPE_REFCOUNTED ?????????(1<<2) ?/* 需要引用计数的类型 */#define IS_TYPE_COLLECTABLE ????????(1<<3) ?/* 可能包含循环引用的类型 */#define IS_TYPE_COPYABLE ???????????(1<<4) ?/* 可被复制的类型 */#define IS_TYPE_SYMBOLTABLE ????????(1<<5) ?/* 符号表类型 */

2.2.3、const_flags

常量类型的标记,对应的属性为:

/* zval.u1.v.const_flags */#define IS_CONSTANT_UNQUALIFIED ????0x010#define IS_LEXICAL_VAR ?????????????0x020#define IS_LEXICAL_REF ?????????????0x040#define IS_CONSTANT_CLASS ??????????0x080 ?/* __CLASS__ in trait */#define IS_CONSTANT_IN_NAMESPACE ???0x100 ?/* used only in opline->extended_value */

2.2.4、type_info

type_info与结构体v共用内存,修改type_info等同于修改结构体v的值,所以type_info是v中四个char的组合。

2.3、u2

本来使用u1和zend_value就可以表示变量的,没有必要定义u2,但是我们来看一下,如果没有u2,在内存对齐的情况下zval内存大小为16个字节,当联合了u2后依然是占用16个字节。既然有或没有占用内存大小相同,不如用它来记录一些附属信息。下面我们来看下u2都存储了哪些内容。

2.3.1、next

用来解决哈希冲突问题,记录冲突的下一个元素位置。

2.3.2、cache_slot

运行时缓存,在执行函数时回去缓存中查找,若缓存中没有则到全局function表中查找。

2.3.3、lineno

文件执行的行号,应用在AST节点上。Zend引擎在词法和语法解析时会把当前执行的文件行号记录下来,记录在zend_ast中的lineno中。

2.3.4、num_args

函数调用时传入函数的参数个数。

2.3.5、fe_pos

用于遍历数组时记录当前遍历的位置,比如每次执行foreach时fe_pos都会加一,当再次调用foreach进行遍历时,fe_post会进行重置。

2.3.6、fe_iter_idx

这个与fe_pos类似,只不过它是针对对象的。对象的属性也是HashTable,传入的参数是对象时,会获取对象的属性,所以遍历对象就是在变量对象的属性。

三、参考文献

  • 《PHP7内核剖析》
  • 《PHP7底层设计和源码实现》
  • 深入理解PHP7内核之zval

跟厂长学PHP内核7(六):变量之zval

原文地址:https://www.cnblogs.com/enochzzg/p/9626946.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved