接下来我会从源码的角度来观察这些现象
看一段简单的代码
$a = 1;
echo "aaaa\n";
然后查到赋值对应的opcode是 ZEND_ASSIGN_SPEC_CV_CONST_HANDLER,在zend_vm_execute.h中找到对应的实现
static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zval *value;
zval **variable_ptr_ptr;
SAVE_OPLINE();
value = opline->op2.zv;
variable_ptr_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC);
if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr_ptr == NULL)) {
if (zend_assign_to_string_offset(&EX_T(opline->op1.var), value, IS_CONST TSRMLS_CC)) {
if (RETURN_VALUE_USED(opline)) {
zval *retval;
ALLOC_ZVAL(retval);
ZVAL_STRINGL(retval, Z_STRVAL_P(EX_T(opline->op1.var).str_offset.str)+EX_T(opline->op1.var).str_offset.offset, 1, 1);
INIT_PZVAL(retval);
EX_T(opline->result.var).var.ptr = retval;
}
} else if (RETURN_VALUE_USED(opline)) {
PZVAL_LOCK(&EG(uninitialized_zval));
EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval);
}
} else if (IS_CV == IS_VAR && UNEXPECTED(*variable_ptr_ptr == &EG(error_zval))) {
if (0) {
zval_dtor(value);
}
if (RETURN_VALUE_USED(opline)) {
PZVAL_LOCK(&EG(uninitialized_zval));
EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval);
}
} else {
if (IS_CONST == IS_TMP_VAR) {
value = zend_assign_tmp_to_variable(variable_ptr_ptr, value TSRMLS_CC);
} else if (IS_CONST == IS_CONST) {
value = zend_assign_const_to_variable(variable_ptr_ptr, value TSRMLS_CC);
} else {
value = zend_assign_to_variable(variable_ptr_ptr, value TSRMLS_CC);
}
if (RETURN_VALUE_USED(opline)) {
PZVAL_LOCK(value);
EX_T(opline->result.var).var.ptr = value;
}
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}