php7的zval相关介绍
时间:2022-07-24
本文章向大家介绍php7的zval相关介绍,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在php7中变量主要由zval保存,只占用16个字节 zval结构如下
struct _zval_struct {
zend_value value; /* value */
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, /* define数据类型 */ /* active type */
zend_uchar type_flags, /* 变量类型特有的标记 */
zend_uchar const_flags, /* 常量类型的标记 */
zend_uchar reserved) /* 保留字段 */ /* call info for EX(This) */
} v;
uint32_t type_info;
} u1;
union {
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的位置 */ /* foreach position */
uint32_t fe_iter_idx; /* foreach游标索引位置 */ /* foreach iterator index */
uint32_t access_flags; /* 用在类中 */ /* class constant access flags */
uint32_t property_guard; /* set get魔术方法中会用到 */ /* single property guard */
uint32_t extra; /* not further specified */
} u2;
};
zval主要由value u1 和u2保存 value占8字节,u1和u2各占4个字节 _zend_value的结构如下:
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;
void *ptr;
zend_class_entry *ce; /* 类 */
zend_function *func; /* 函数 */
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
u1中的type用来区分数据类型,从而映射到_zend_value中的不同类型,type的类型关系如下
/* 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
纸上得来终觉浅 ,我们直接来用gdb实战一下看看内部的运行过程 我们编写这样一段程序zval.php,用echo来打断点,来查看php的变量相关的保存
$a = 100;
echo $a;
$b=2.3;
echo $b;
$c = null;
echo $c;
$d = true;
echo $d;
$e = false;
echo $e;
$f = "string";
echo $f;
$g = [1, 2, 3];
echo $g;
$h = new stdclass();
echo $h;
用gdb命令执行 在echo打断点
[root@VM_0_4_centos zval]# gdb ../php-7.1.9/bin/php
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/php/php-7.1.9/bin/php...done.
(gdb) b ZEND_ECHO_SPEC_CV_HANDLER
Breakpoint 1 at 0x8f76a7: file /download/php-7.1.9/Zend/zend_vm_execute.h, line 34699.
(gdb) r zval.php
Starting program: /home/php/zval/../php-7.1.9/bin/php zval.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib64/libthread_db.so.1".
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER () at /download/php-7.1.9/Zend/zend_vm_execute.h:34699
34699 SAVE_OPLINE();
Missing separate debuginfos, use: debuginfo-install glibc-2.17-196.el7_4.2.x86_64 libxml2-2.9.1-6.el7_2.3.x86_64 nss-softokn-freebl-3.34.0-2.el7.x86_64 xz-libs-5.2.2-1.el7.x86_64 zlib-1.2.7-17.el7.x86_64
(gdb) n
34700 z = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
(gdb) n
34702 if (Z_TYPE_P(z) == IS_STRING) {
(gdb) p *z
$1 = {value = {lval = 100, dval = 4.9406564584124654e-322, counted = 0x64, str = 0x64, arr = 0x64, obj = 0x64, res = 0x64, ref = 0x64, ast = 0x64, zv = 0x64, ptr = 0x64,
ce = 0x64, func = 0x64, ww = {w1 = 100, w2 = 0}}, u1 = {v = {type = 4 ' 04', type_flags = 0 ' 00', const_flags = 0 ' 00', reserved = 0 ' 00'}, type_info = 4}, u2 = {
next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0, property_guard = 0, extra = 0}}
(gdb)
最后的p *z中我们可以看到 u1的type是4,对应的是IS_LONG整型,所以直接取value中的lval 值为100
(gdb) c
Continuing.
100
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER () at /download/php-7.1.9/Zend/zend_vm_execute.h:34699
34699 SAVE_OPLINE();
(gdb) n
34700 z = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
(gdb) n
34702 if (Z_TYPE_P(z) == IS_STRING) {
(gdb) p *z
$1 = {value = {lval = 4612361558371493478, dval = 2.2999999999999998, counted = 0x4002666666666666, str = 0x4002666666666666, arr = 0x4002666666666666, obj = 0x4002666666666666,
res = 0x4002666666666666, ref = 0x4002666666666666, ast = 0x4002666666666666, zv = 0x4002666666666666, ptr = 0x4002666666666666, ce = 0x4002666666666666,
func = 0x4002666666666666, ww = {w1 = 1717986918, w2 = 1073899110}}, u1 = {v = {type = 5 ' 05', type_flags = 0 ' 00', const_flags = 0 ' 00', reserved = 0 ' 00'},
type_info = 5}, u2 = {next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0, property_guard = 0, extra = 0}}
(gdb) p *z
$2 = {value = {lval = 17788064, dval = 8.7884713284254274e-317, counted = 0x10f6ca0, str = 0x10f6ca0, arr = 0x10f6ca0, obj = 0x10f6ca0, res = 0x10f6ca0, ref = 0x10f6ca0,
ast = 0x10f6ca0, zv = 0x10f6ca0, ptr = 0x10f6ca0, ce = 0x10f6ca0, func = 0x10f6ca0, ww = {w1 = 17788064, w2 = 0}}, u1 = {v = {type = 1 ' 01', type_flags = 0 ' 00',
const_flags = 0 ' 00', reserved = 0 ' 00'}, type_info = 1}, u2 = {next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0,
property_guard = 0, extra = 0}}
(gdb) c
Continuing.
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER () at /download/php-7.1.9/Zend/zend_vm_execute.h:34699
34699 SAVE_OPLINE();
(gdb) n
34700 z = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
(gdb) n
34702 if (Z_TYPE_P(z) == IS_STRING) {
(gdb) p *z
$3 = {value = {lval = 17788064, dval = 8.7884713284254274e-317, counted = 0x10f6ca0, str = 0x10f6ca0, arr = 0x10f6ca0, obj = 0x10f6ca0, res = 0x10f6ca0, ref = 0x10f6ca0,
ast = 0x10f6ca0, zv = 0x10f6ca0, ptr = 0x10f6ca0, ce = 0x10f6ca0, func = 0x10f6ca0, ww = {w1 = 17788064, w2 = 0}}, u1 = {v = {type = 3 ' 03', type_flags = 0 ' 00',
const_flags = 0 ' 00', reserved = 0 ' 00'}, type_info = 3}, u2 = {next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0,
property_guard = 0, extra = 0}}
(gdb) c
Continuing.
1
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER () at /download/php-7.1.9/Zend/zend_vm_execute.h:34699
34699 SAVE_OPLINE();
(gdb) n
34700 z = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
(gdb) n
34702 if (Z_TYPE_P(z) == IS_STRING) {
(gdb) p *z
$4 = {value = {lval = 17788064, dval = 8.7884713284254274e-317, counted = 0x10f6ca0, str = 0x10f6ca0, arr = 0x10f6ca0, obj = 0x10f6ca0, res = 0x10f6ca0, ref = 0x10f6ca0,
ast = 0x10f6ca0, zv = 0x10f6ca0, ptr = 0x10f6ca0, ce = 0x10f6ca0, func = 0x10f6ca0, ww = {w1 = 17788064, w2 = 0}}, u1 = {v = {type = 2 ' 02', type_flags = 0 ' 00',
const_flags = 0 ' 00', reserved = 0 ' 00'}, type_info = 2}, u2 = {next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0,
property_guard = 0, extra = 0}}
这三次执行u1的type对应的是1(IS_NULL) 3(IS_TRUE) 2(IS_FALSE) 不需要去value中取值
(gdb) n
34700 z = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
(gdb) n
34702 if (Z_TYPE_P(z) == IS_STRING) {
(gdb) p *z
$5 = {value = {lval = 17733632, dval = 8.7615783471909966e-317, counted = 0x10e9800, str = 0x10e9800, arr = 0x10e9800, obj = 0x10e9800, res = 0x10e9800, ref = 0x10e9800,
ast = 0x10e9800, zv = 0x10e9800, ptr = 0x10e9800, ce = 0x10e9800, func = 0x10e9800, ww = {w1 = 17733632, w2 = 0}}, u1 = {v = {type = 6 ' 06', type_flags = 0 ' 00',
const_flags = 0 ' 00', reserved = 0 ' 00'}, type_info = 6}, u2 = {next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0,
property_guard = 0, extra = 0}}
(gdb) p *$5.value.str
$6 = {gc = {refcount = 1, u = {v = {type = 6 ' 06', flags = 7 'a', gc_info = 0}, type_info = 1798}}, h = 9223378990886268924, len = 6, val = "s"}
(gdb) p *$5.value.str.val@6
$7 = "string"
u1对应的type是6 字符串型,可以通过 p *
5.value.str
(gdb) p *z
$2 = {value = {lval = 140737314653024, dval = 6.9533472258009033e-310, counted = 0x7ffff5a58360, str = 0x7ffff5a58360, arr = 0x7ffff5a58360, obj = 0x7ffff5a58360,
res = 0x7ffff5a58360, ref = 0x7ffff5a58360, ast = 0x7ffff5a58360, zv = 0x7ffff5a58360, ptr = 0x7ffff5a58360, ce = 0x7ffff5a58360, func = 0x7ffff5a58360, ww = {w1 = 4121264992,
w2 = 32767}}, u1 = {v = {type = 7 'a', type_flags = 28 ' 34', const_flags = 0 ' 00', reserved = 0 ' 00'}, type_info = 7175}, u2 = {next = 0, cache_slot = 0, lineno = 0,
num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0, property_guard = 0, extra = 0}}
(gdb) c
Continuing.
Array
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER () at /download/php-7.1.9/Zend/zend_vm_execute.h:34699
34699 SAVE_OPLINE();
(gdb) n
34700 z = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
(gdb) n
34702 if (Z_TYPE_P(z) == IS_STRING) {
(gdb) p *z
$3 = {value = {lval = 140737314680496, dval = 6.9533472271582005e-310, counted = 0x7ffff5a5eeb0, str = 0x7ffff5a5eeb0, arr = 0x7ffff5a5eeb0, obj = 0x7ffff5a5eeb0,
res = 0x7ffff5a5eeb0, ref = 0x7ffff5a5eeb0, ast = 0x7ffff5a5eeb0, zv = 0x7ffff5a5eeb0, ptr = 0x7ffff5a5eeb0, ce = 0x7ffff5a5eeb0, func = 0x7ffff5a5eeb0, ww = {w1 = 4121292464,
w2 = 32767}}, u1 = {v = {type = 8 'b', type_flags = 12 'f', const_flags = 0 ' 00', reserved = 0 ' 00'}, type_info = 3080}, u2 = {next = 0, cache_slot = 0, lineno = 0,
num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0, property_guard = 0, extra = 0}}
后面两次根据u1的type来看分别是数组和对象类型
- Linux Token Auth 一次性密码认证
- WPF备忘录(7)WPF图片资源路径介绍
- 植入式攻击入侵检测解决方案
- 神经网络太臃肿?教你如何将神经网络减小四分之一
- WPF中ListView如何改变选中条背景颜色
- WPF Trigger for IsSelected in a DataTemplate for ListBox items
- C#基础知识回顾--BackgroundWorker介绍
- Elasticsearch 瞬间入门
- 使用OpenLDAP 操作 Windows Active Directory
- 优化算法:到底是数学还是代码?
- Email 服务器之 SPF 记录
- WPF中播放声音媒体文件
- 设计模式学习--装饰者模式(Decorator Pattern)
- SQL Server 存储过程
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- ngrokc rampis预编译版本 By HKL, Fr
- megacli修复raid1硬盘 By HKL, Tues
- DNSPOD自动更新公网IP脚本 By HKL, Wedn
- Zerotier网卡NAT via iptables By HKL,
- Github Pages同步到Qcloud腾讯云对象存储COS By HKL,
- 独家 | 探索性文本数据分析的新手教程(Amazon案例研究)
- OpenWRT通过3G Modem加asterisk将GSM通话转为SIP By HKL,
- Coding通过Jenkins生成jekyll并发布到腾讯云对象存储Qcloud COS By HKL,
- mybatis 实用技巧:<trim prefix="where" prefixOverrides="and|or">
- OpenWRT配置Webdav(s)共享文件 By HKL,
- OpenWRT配置Apache Webdav By HKL,
- 我向面试官讲解了单例模式,他对我竖起了大拇指
- 47 张图带你 MySQL 进阶!!!
- 新特性解读 | InnoDB-Cluster 扫盲-日常运维
- Laravel 框架实现无限极分类