美文网首页PHPPHP经验分享
PHP7源码学习笔记(四) HashTable赋值的具体工作过程

PHP7源码学习笔记(四) HashTable赋值的具体工作过程

作者: 公式般欢笑 | 来源:发表于2020-03-03 01:09 被阅读0次

源码版本:php-7.1.0
电脑环境:Deepin15.11
GDB版本:8.3.1
GCC版本:6.3.0
依然使用一段代码来进行分析

<?php
$a=[];
$a[]='124';
$a[]='236';

查看gdb信息可以发现ZEND虚拟机一共执行了以下四条指令:

ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:39440
ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_DATA_CONST_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:42221
ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_DATA_CONST_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:42221
ZEND_RETURN_SPEC_CONST_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:2858

第一个HANDLER所对应的函数为:

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE
    zval *value;
    zval *variable_ptr;
    SAVE_OPLINE();
    value = EX_CONSTANT(opline->op2);
    variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var);
    if (IS_CV == IS_VAR && UNEXPECTED(Z_ISERROR_P(variable_ptr))) {
        if (UNEXPECTED(0)) {
            ZVAL_NULL(EX_VAR(opline->result.var));
        }
    } else {
        value = zend_assign_to_variable(variable_ptr, value, IS_CONST);
        if (UNEXPECTED(0)) {
            ZVAL_COPY(EX_VAR(opline->result.var), value);
        }

        /* zend_assign_to_variable() always takes care of op2, never free it! */
    }

    ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

这个函数的操作是将我们opline->op2中对应的value,也就是我们要赋值到a的那个空数组。 而opline->op1.val存储的就是‘a’这个变量,所以在此操作之后,就是将$a变成了一个空数组。

第二条和第三条指令所对应的函数为:

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    zval *object_ptr;

    zval *value;
    zval *variable_ptr;
    zval *dim;

    SAVE_OPLINE();
    object_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var);//从opline中取出当前需要赋值的变量,因为我们之前初始化的是array所以此处一定也是array.
//下面的内容只走if判断,所以把else删掉

    if (EXPECTED(Z_TYPE_P(object_ptr) == IS_ARRAY)) {
try_assign_dim_array:
        SEPARATE_ARRAY(object_ptr);
        if (IS_UNUSED == IS_UNUSED) {
            variable_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(object_ptr), &EG(uninitialized_zval));
            if (UNEXPECTED(variable_ptr == NULL)) {
                zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
                goto assign_dim_error;
            }
        } else {
            dim = NULL;
            if (IS_UNUSED == IS_CONST) {
                variable_ptr = zend_fetch_dimension_address_inner_W_CONST(Z_ARRVAL_P(object_ptr), dim);
            } else {
                variable_ptr = zend_fetch_dimension_address_inner_W(Z_ARRVAL_P(object_ptr), dim);
            }
            if (UNEXPECTED(variable_ptr == NULL)) {
                goto assign_dim_error;
            }
        }
        value = EX_CONSTANT((opline+1)->op1);
        value = zend_assign_to_variable(variable_ptr, value, IS_CONST);
        if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
            ZVAL_COPY(EX_VAR(opline->result.var), value);
        }
    } else {
            //...
    }
    if (IS_UNUSED != IS_UNUSED) {

    }

    /* assign_dim has two opcodes! */
    ZEND_VM_NEXT_OPCODE_EX(1, 2);
}

在这个函数中,首先通过zend_hash_next_index_insert初始化数组对应下一个位置的指针。
然后解析赋值的变量,并通过zend_assign_to_variable将值赋予初始化的指针。
然后走到了ZEND_RETURN_SPEC_CONST_HANDLER这个函数,所有指令解析完成。

相关文章

网友评论

    本文标题:PHP7源码学习笔记(四) HashTable赋值的具体工作过程

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