PHP7内核(六):变量之zval
记得网上流传甚广的段子“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
PHP7内核(六):变量之zval的更多相关文章
- 《PHP内核剖析 - 变量/内存管理》
本文总结自: <PHP7 内核剖析 - 变量的内部实现> 一:变量的实现 - 变量是一个语言实现的基础. - 在PHP中,变量的组成部分为 变量名(zval) 变量值(zend_value ...
- 跟厂长学PHP7内核(六):变量之zval
记得网上流传甚广的段子"PHP是世界上最好的语言",暂且不去讨论是否言过其实,但至少PHP确实有独特优势的,比如它的弱类型,即只需要$符号即可声明变量,使得PHP入手门槛极低,成为 ...
- 跟厂长学PHP7内核(七):常见变量类型的基本结构
上篇文章讲述了变量的存储结构zval,今天我们就来学习一下几个常见变量类型的基本结构. 一.类型一览 zval中的u1.v.type用来存储变量的类型,而zval.value存储的是不同类型对应的值, ...
- 深入剖析PHP7内核源码(二)- PHP变量容器
简介 PHP的变量使用起来非常方便,其基本结构是底层实现的zval,PHP7采用了全新的zval,由此带来了非常大的性能提升,本文重点分析PHP7的zval的改变. PHP5时代的ZVAL typed ...
- PHP7内核(七):常见变量类型的基本结构
上篇文章讲述了变量的存储结构zval,今天我们就来学习一下几个常见变量类型的基本结构. 一.类型一览 zval中的u1.v.type用来存储变量的类型,而zval.value存储的是不同类型对应的值, ...
- 跟厂长学PHP7内核(八):深入理解字符串的实现
在前面大致预览了常用变量的结构之后,我们今天来仔细的剖析一下字符串的具体实现. 一.字符串的结构 struct _zend_string { zend_refcounted_h gc; /* 字符串类 ...
- PHP7内核(八):深入理解字符串的实现
在前面大致预览了常用变量的结构之后,我们今天来仔细的剖析一下字符串的具体实现. 一.字符串的结构 struct _zend_string { zend_refcounted_h gc; /* 字符串类 ...
- 深入理解PHP内核(七)变量及数据类型-常量
原文链接:http://www.orlion.ga/246/ 在PHP中,常量的名字是一个简单值的标识符,在脚本执行期间该值不能改变.和变量一样,常量默认为大小写敏感,但是通常是大写的. 常量是在变量 ...
- 深入理解PHP内核(五)变量及数据类型-变量的结构和类型
原文链接:http://www.orlion.ga/238/ 编程语言的类型可以分为强类型和弱类型两种,PHP是弱类型语言,但是C语言是强类型语言.在官网PHP实现内部,所有变量使用同一种数据结构(z ...
随机推荐
- Java GUI记账本(基于Mysql&&文件存储两种版本)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.java * 作者:常轩 * 微信公众号:Worldh ...
- IP 地址与MAC硬件地址
IP 地址与MAC硬件地址 我们都知道数据通信要使用IP地址加MAC地址,两个地址缺一不可,下为原理图: 1.下面介绍计算机A与计算机B通信的过程 交换机基于数据帧的MAC地址转发数据帧,路由器基于数 ...
- 探究Java中的引用
探究Java中的四种引用 从JDK1.2版本开始,Java把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用.本篇就来详细探究 ...
- Day 3 DP
1. P1015 精卫填海 01背包 + 判断 #include <iostream> using namespace std; , MAXV = ; int v, n, m, f[MAX ...
- Java基础--Arrays类
Arrays工具类:用来操作数组(比如排序和搜索)的各种方法 常用方法: 使用二分法查找 Arrays.binarySearch(int[]array,int value); 数组内容转换成字符串的形 ...
- webpack进阶(三)
1)CommonsChunkPlugin已经从webpack4移除,所以在用webpack进行公共模块的拆分时,会报错 Cannot read property 'CommonsChunkPlugin ...
- 什么是RPM
RPM是RedHat Package Manager(RedHat软件包管理工具)的缩写,这一文件格式名称虽然打上了RedHat的标志,但是其原始设计理念是开放式的,现在包括OpenLinux.S.u ...
- [项目分享]JSP+Servlet+JDBC实现的云端汽修后台管理系统
本文存在视频版本,请知悉 项目简介 项目来源于:https://gitee.com/chenlinSir/CloudDemo-servlet 难度等级:简单 基于JSP+Servlet+Jdbc的云端 ...
- 计算属性(computed)+侦听器(watch)+ 方法(methods)
计算属性 computed 当数据改变时,方法的结果也会发生改变.如果多处地方调用计算属性里面的同一个方法时,该方法只会执行一次.如图,在控制台改变data里面的num值时,虽然在多处使用comput ...
- 建议5:比较function语句和function表达式
在Javascript语言中,既有function语句,也有函数表达式,这是令人困惑的.因为它们看起来是相同的.一个function语句就是一个值为一个函数的var语句的简写形式. 下面语句: fun ...