美文网首页PHPPHP经验分享
PHP7源码学习笔记(一) zval类型

PHP7源码学习笔记(一) zval类型

作者: 公式般欢笑 | 来源:发表于2020-02-26 14:46 被阅读0次

    源码版本:php-7.1.0
    电脑环境:Deepin15.11
    GDB版本:8.3.1
    GCC版本:6.3.0

    PHP的zval数据结构

    PHP中的所有变量,都会保存在一个zval结构体中。

    
    typedef struct _zval_struct zval; 
    
    

    具体的结构体内容为:

    struct _zval_struct {
        zend_value        value;        
        union {
            struct {
                ZEND_ENDIAN_LOHI_4( //这里是用来区分大小端的
                    zend_uchar    type,      /* type是用于标注变量的类型 */
                    ...
            } v;
            uint32_t type_info;
        } u1;
        union {
              ...
        } u2;
    };
    

    _zval_struct结构体包含三个内容,value u1和u2。
    value 变量包含的具体数据,u1用来区分变量的类型,u2是一个辅助工具。
    其中,u1的type一共有10个值,对应PHP中的几种数据类型。

    #define IS_UNDEF                    0  //undefined
    #define IS_NULL                     1  //null
    #define IS_FALSE                    2  //false
    #define IS_TRUE                     3  //true
    #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  //引用
    

    zval中的value内容是这样的一个结构体,除long类型和double类型之外,都是通过指针的方式来实现的。

    typedef union _zend_value {
        zend_long         lval;             /* long value */
        double            dval;             /* double value */
        zend_refcounted  *counted;
        zend_string      *str;
        zend_array       *arr;
        zend_object      *obj;
        ...
        zend_function    *func;
        struct {
            uint32_t w1;
            uint32_t w2;
        } ww;
    } zend_value;
    

    指针类型的zend_string、zend_array、zend_object均有结构体的定义,以zend_string为例:

    struct _zend_string {
        zend_refcounted_h gc;               // 引用计数
        zend_ulong        h;                /* hash value */
        size_t            len;
        char              val[1];           //可变长度的字符串内容
    };
    

    通过GDB深入理解PHP的数据结构

    当一个变量被分配的时候,首先会初始化一个空的zval,u1的type为IS_UNDEF。然后在进行语法解析的时候,根据值来判断变量的类型,更改zval.u1.type为对应类型。同时将变量值赋值给value中的对应字段。
    我们可以通过一段PHP代码来操作一下PHP的zval类型。

    <?php
       $a=1;
       echo $a;
    

    通过gdb来启动PHP,然后在echo处打下断点

    (gdb) b ZEND_ECHO_SPEC_CV_HANDLER 
    Breakpoint 1 at 0x5bdf2f: file /program/php-7.1.0/Zend/zend_vm_execute.h, line 34640.
    

    运行 php文件

    (gdb) r echo.php 
    Starting program: /program/bin/php/php7/bin/php echo.php
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    
    Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:34640
    34640       SAVE_OPLINE();
    

    继续执行下一步,取出当前的变量

    (gdb) n
    34641       z = _get_zval_ptr_cv_undef(execute_data, opline->op1.var);
    (gdb) 
    34643       if (Z_TYPE_P(z) == IS_STRING) {
    (gdb) p z
    $1 = (zval *) 0x7ffff3814080
    (gdb) p *z
    $2 = {value = {lval = 1, dval = 4.9406564584124654e-324, counted = 0x1, str = 0x1, arr = 0x1, obj = 0x1, res = 0x1, ref = 0x1, ast = 0x1, zv = 0x1, ptr = 0x1, ce = 0x1, func = 0x1, ww = {w1 = 1, 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}}
    

    可以看到当前的变量的u1.type为4,并且其value.lval为1。

    (gdb) n
    34650           zend_string *str = _zval_get_string_func(z); //这里是将内容强转为字符串
    (gdb) 
    34652           if (ZSTR_LEN(str) != 0) {
    (gdb) p str
    $3 = (zend_string *) 0x7ffff3802d40
    (gdb) p *str
    $4 = {gc = {refcount = 1, u = {v = {type = 6 '\006', flags = 0 '\000', gc_info = 0}, type_info = 6}}, h = 0, len = 1, val = "1"}
    

    最终 $4的结果,对应的正是zend_string的结构体。

    相关文章

      网友评论

        本文标题:PHP7源码学习笔记(一) zval类型

        本文链接:https://www.haomeiwen.com/subject/qzfmchtx.html