<?php
$a=1;
$b=&a;
$c=2;
$d=$c;
$c=$b;
结论:
保存左值的指针,为内存回收做准备,同时该指针会被再次赋值
1)左值不是一个引用
1.1)如果左值 refcount_gc为1,说明左值被赋过值,
1.1.1)右值为引用 ,进入第2步
1.1.2)右值不是引用,refcount_gc加1,将右值拷贝给左值
1.2)如果不为1,说明第一次出现,或者被别的变量共同使用了 zval, 其refcount_gc减1 ,将左值GC buffer中 (由GC判断是否需要释放内存)
1.2.1)右值为引用 ,分配内存给左值,拷贝右值的value给左值,并将右值的value.str.val进行深拷贝,refcount_gc设置1
1.2.2)右值不是引用,直接将右值拷贝给左值,refcount_gc加1
2)左值是一个引用,说明前面左值被赋过值,将左值使用构析函数,回收内存,将右值的vaue拷贝给左值,并深拷贝右值的value.str.val
<?php $a=1; $b=&$a; $c=2; $b=$c;
static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *value; zval **variable_ptr_ptr; SAVE_OPLINE(); value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op2.var TSRMLS_CC); variable_ptr_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), 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_CV 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); AI_SET_PTR(&EX_T(opline->result.var), retval); } } else if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(&EG(uninitialized_zval)); AI_SET_PTR(&EX_T(opline->result.var), &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)); AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } } else { if (IS_CV == IS_TMP_VAR) { value = zend_assign_tmp_to_variable(variable_ptr_ptr, value TSRMLS_CC); } else if (IS_CV == 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); AI_SET_PTR(&EX_T(opline->result.var), value); } } /* zend_assign_to_variable() always takes care of op2, never free it! */ CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); }
static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC) { zval *variable_ptr = *variable_ptr_ptr; zval garbage; if (Z_TYPE_P(variable_ptr) == IS_OBJECT && UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) { Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC); return variable_ptr; } if (EXPECTED(!PZVAL_IS_REF(variable_ptr))) { if (Z_REFCOUNT_P(variable_ptr)==1) { if (UNEXPECTED(variable_ptr == value)) { return variable_ptr; } else if (EXPECTED(!PZVAL_IS_REF(value))) { Z_ADDREF_P(value); *variable_ptr_ptr = value; if (EXPECTED(variable_ptr != &EG(uninitialized_zval))) { GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr); zval_dtor(variable_ptr); efree(variable_ptr); } else { Z_DELREF_P(variable_ptr); } return value; } else { goto copy_value; } } else { /* we need to split */ Z_DELREF_P(variable_ptr); GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr); if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) { ALLOC_ZVAL(variable_ptr); *variable_ptr_ptr = variable_ptr; INIT_PZVAL_COPY(variable_ptr, value); zval_copy_ctor(variable_ptr); return variable_ptr; } else { *variable_ptr_ptr = value; Z_ADDREF_P(value); Z_UNSET_ISREF_P(value); return value; } } } else { if (EXPECTED(variable_ptr != value)) { copy_value: if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) { /* nothing to destroy */ ZVAL_COPY_VALUE(variable_ptr, value); zendi_zval_copy_ctor(*variable_ptr); } else { ZVAL_COPY_VALUE(&garbage, variable_ptr); ZVAL_COPY_VALUE(variable_ptr, value); zendi_zval_copy_ctor(*variable_ptr); _zval_dtor_func(&garbage ZEND_FILE_LINE_CC); } } return variable_ptr; } }
//zend.h #define INIT_PZVAL_COPY(z, v) do { ZVAL_COPY_VALUE(z, v); Z_SET_REFCOUNT_P(z, 1); Z_UNSET_ISREF_P(z); } while (0)
static zend_always_inline zend_bool zval_unset_isref_p(zval* pz) {
return pz->is_ref__gc = 0;
}
变量赋值(非引用) php内核的实现(三),布布扣,bubuko.com
原文地址:http://www.cnblogs.com/taek/p/3837398.html