变量赋值(非引用) 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;
 }

 

变量赋值(非引用) php内核的实现(三),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。