源码版本: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’这个变量,所以在此操作之后,就是将$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这个函数,所有指令解析完成。
网友评论