首页 > 代码库 > 变量赋值(非引用) php内核的实现(三)

变量赋值(非引用) php内核的实现(三)

<?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;
 }