前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >php7的zval相关介绍

php7的zval相关介绍

作者头像
程序员小饭
发布2020-09-07 15:30:03
4290
发布2020-09-07 15:30:03
举报
文章被收录于专栏:golang+php

在php7中变量主要由zval保存,只占用16个字节 zval结构如下

代码语言:javascript
复制
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的结构如下:

代码语言:javascript
复制
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的类型关系如下

代码语言:javascript
复制
/* 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的变量相关的保存

代码语言:javascript
复制
$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打断点

代码语言:javascript
复制
[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 '\004', type_flags = 0 '\000', const_flags = 0 '\000', reserved = 0 '\000'}, 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

代码语言:javascript
复制
(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 '\005', type_flags = 0 '\000', const_flags = 0 '\000', reserved = 0 '\000'},
    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}}
代码语言:javascript
复制
(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 '\001', type_flags = 0 '\000',
      const_flags = 0 '\000', reserved = 0 '\000'}, 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 '\003', type_flags = 0 '\000',
      const_flags = 0 '\000', reserved = 0 '\000'}, 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 '\002', type_flags = 0 '\000',
      const_flags = 0 '\000', reserved = 0 '\000'}, 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中取值

代码语言:javascript
复制
(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 '\006', type_flags = 0 '\000',
      const_flags = 0 '\000', reserved = 0 '\000'}, 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 '\006', 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的方式获得string的对象,通过p *
5.value.str的方式获得string的对象,通过p *

5.value.str

代码语言:javascript
复制
(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 '\034', const_flags = 0 '\000', reserved = 0 '\000'}, 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 '\000', reserved = 0 '\000'}, 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来看分别是数组和对象类型

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档