zoukankan      html  css  js  c++  java
  • 变量赋值(引用) php内核的实现(二)

    <?php
    $a=1;
    $b=&$a;
    $c=2;
    $a=&$c;
    echo $a." ";
    echo $b;

    2

    1

    结论:

    首先保存 左值的内存地址, 因这个内存地址会被再次被赋值

    1)右值是引用

      进入2.2 2.3 2.4步骤

      例子:

    <?php
      $a=1;
      $c=2;   
    $b=&$a; //执行到这里时,属于第2种情况   $c=&$a; //执行到这里时,属于第1种情况,

    2)右值不是引用,右值的refcount_gc减1

      2.1)如果refcount_gc减1,大于0 ,说明有别的变量也共同使用了zval,需要单独分配内存给右值

      2.2)将右值(内存地址)赋值给左值

      2.3)refcount_gc 加1,并设置 is_ref=1 

      2.4)销毁左值

        2.3.1)将上面保存的左值的zval的refcount_gc减1

          2.3.1.1)上面值为0,则zval_dtor

          2.3.1.2)上面值大于0,则进入GC buffer, 但zval类型必须为 object或 array

      

     

    可以发现$a,$b,$c全是CV变量

    当php解释器执行到$b=&$a时,会执行到下面的handler

    static int ZEND_FASTCALL  ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
        zend_free_op free_op2;
        zval **variable_ptr_ptr;
        zval **value_ptr_ptr;
    
        SAVE_OPLINE();
        value_ptr_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op2.var TSRMLS_CC);
    
        if (IS_CV == IS_VAR &&
            value_ptr_ptr &&
            !Z_ISREF_PP(value_ptr_ptr) &&
            opline->extended_value == ZEND_RETURNS_FUNCTION &&
            !EX_T(opline->op2.var).var.fcall_returned_reference) {
            if (free_op2.var == NULL) {
                PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */
            }
            zend_error(E_STRICT, "Only variables should be assigned by reference");
            if (UNEXPECTED(EG(exception) != NULL)) {
    
                HANDLE_EXCEPTION();
            }
            return ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
        } else if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
            PZVAL_LOCK(*value_ptr_ptr);
        }
        if (IS_CV == IS_VAR && UNEXPECTED(EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr)) {
            zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object");
        }
    
        variable_ptr_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC);
        if ((IS_CV == IS_VAR && UNEXPECTED(value_ptr_ptr == NULL)) ||
            (IS_CV == IS_VAR && UNEXPECTED(variable_ptr_ptr == NULL))) {
            zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects");
        }
        zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); //在这里执行分配的操作
    
        if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
            Z_DELREF_PP(variable_ptr_ptr);
        }
    
        if (RETURN_VALUE_USED(opline)) {
            PZVAL_LOCK(*variable_ptr_ptr);
            AI_SET_PTR(&EX_T(opline->result.var), *variable_ptr_ptr);
        }
    
    
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
    }
    static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **value_ptr_ptr TSRMLS_DC)
    {
        zval *variable_ptr = *variable_ptr_ptr;    
        zval *value_ptr = *value_ptr_ptr;       
    
        if (variable_ptr == &EG(error_zval) || value_ptr == &EG(error_zval)) {
            variable_ptr_ptr = &EG(uninitialized_zval_ptr);
        } else if (variable_ptr != value_ptr) {
            if (!PZVAL_IS_REF(value_ptr)) { //此时右值不是一个引用
                /* break it away */
                Z_DELREF_P(value_ptr);  //refcount_gc减1 的作用 是看 是否还有其他变量也使用了valu_ptr_ptr对应的zval,如果有,则重新分配zval
                if (Z_REFCOUNT_P(value_ptr)>0) {
                    ALLOC_ZVAL(*value_ptr_ptr);
                    ZVAL_COPY_VALUE(*value_ptr_ptr, value_ptr);
                    value_ptr = *value_ptr_ptr;
                    zendi_zval_copy_ctor(*value_ptr);
                }
                Z_SET_REFCOUNT_P(value_ptr, 1);  //因为上面减1了,所以这里要加1,
                Z_SET_ISREF_P(value_ptr);//设置 is_ref为1
            }
    
            *variable_ptr_ptr = value_ptr; //将variable_ptr_ptr这个地址指针内容 为 1 的地址
            Z_ADDREF_P(value_ptr); //还要将 refcount_gc加1
    
            zval_ptr_dtor(&variable_ptr); //根据情况释放内存
    }
    else if (!Z_ISREF_P(variable_ptr)) { if (variable_ptr_ptr == value_ptr_ptr) { SEPARATE_ZVAL(variable_ptr_ptr); } else if (variable_ptr==&EG(uninitialized_zval) || Z_REFCOUNT_P(variable_ptr)>2) { /* we need to separate */ Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - 2); ALLOC_ZVAL(*variable_ptr_ptr); ZVAL_COPY_VALUE(*variable_ptr_ptr, variable_ptr); zval_copy_ctor(*variable_ptr_ptr); *value_ptr_ptr = *variable_ptr_ptr; Z_SET_REFCOUNT_PP(variable_ptr_ptr, 2); } Z_SET_ISREF_PP(variable_ptr_ptr); } }
    //zend_variables.c
    
    ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC)
    {
        switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
            case IS_RESOURCE: {
                    TSRMLS_FETCH();
    
                    zend_list_addref(zvalue->value.lval);
                }
                break;
            case IS_BOOL:
            case IS_LONG:
            case IS_NULL:
                break;
            case IS_CONSTANT:
            case IS_STRING:
                CHECK_ZVAL_STRING_REL(zvalue);
                if (!IS_INTERNED(zvalue->value.str.val)) {
                    zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len);
                }
                break;
            case IS_ARRAY:
            case IS_CONSTANT_ARRAY: {
                    zval *tmp;
                    HashTable *original_ht = zvalue->value.ht;
                    HashTable *tmp_ht = NULL;
                    TSRMLS_FETCH();
    
                    if (zvalue->value.ht == &EG(symbol_table)) {
                        return; /* do nothing */
                    }
                    ALLOC_HASHTABLE_REL(tmp_ht);
                    zend_hash_init(tmp_ht, zend_hash_num_elements(original_ht), NULL, ZVAL_PTR_DTOR, 0);
                    zend_hash_copy(tmp_ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
                    zvalue->value.ht = tmp_ht;
                }
                break;
            case IS_OBJECT:
                {
                    TSRMLS_FETCH();
                    Z_OBJ_HT_P(zvalue)->add_ref(zvalue TSRMLS_CC);
                }
                break;
        }
    }
    //zend_API.h
    
    #define CHECK_ZVAL_STRING_REL(z) 
        if (Z_STRVAL_P(z)[ Z_STRLEN_P(z) ] != '') { zend_error(E_WARNING, "String is not zero-terminated (%s) (source: %s:%d)", Z_STRVAL_P(z) ZEND_FILE_LINE_RELAY_CC); }
    //zend_alloc.h
    
    #define estrndup_rel(s, length)                    _estrndup((s), (length) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC)
    //zend_alloc.c
    
    ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    {
        char *p;
    #ifdef ZEND_SIGNALS
        TSRMLS_FETCH();
    #endif
    
        HANDLE_BLOCK_INTERRUPTIONS();
    
        p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
        if (UNEXPECTED(p == NULL)) {
            HANDLE_UNBLOCK_INTERRUPTIONS();
            return p;
        }
        memcpy(p, s, length);
        p[length] = 0;
        HANDLE_UNBLOCK_INTERRUPTIONS();
        return p;
    }
    //zend_execute_API.c
    ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC) /* {{{ */ { #if DEBUG_ZEND>=2 printf("Reducing refcount for %x (%x): %d->%d ", *zval_ptr, zval_ptr, Z_REFCOUNT_PP(zval_ptr), Z_REFCOUNT_PP(zval_ptr) - 1); #endif Z_DELREF_PP(zval_ptr); if (Z_REFCOUNT_PP(zval_ptr) == 0) { TSRMLS_FETCH(); if (*zval_ptr != &EG(uninitialized_zval)) { GC_REMOVE_ZVAL_FROM_BUFFER(*zval_ptr); zval_dtor(*zval_ptr); efree_rel(*zval_ptr); } } else { TSRMLS_FETCH(); if (Z_REFCOUNT_PP(zval_ptr) == 1) { Z_UNSET_ISREF_PP(zval_ptr); } GC_ZVAL_CHECK_POSSIBLE_ROOT(*zval_ptr); } }
    //zend_variables.c
    
    ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC)
    {
        switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
            case IS_STRING:
            case IS_CONSTANT:
                CHECK_ZVAL_STRING_REL(zvalue);
                STR_FREE_REL(zvalue->value.str.val);
                break;
            case IS_ARRAY:
            case IS_CONSTANT_ARRAY: {
                    TSRMLS_FETCH();
    
                    if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) {
                        /* break possible cycles */
                        Z_TYPE_P(zvalue) = IS_NULL;
                        zend_hash_destroy(zvalue->value.ht);
                        FREE_HASHTABLE(zvalue->value.ht);
                    }
                }
                break;
            case IS_OBJECT:
                {
                    TSRMLS_FETCH();
    
                    Z_OBJ_HT_P(zvalue)->del_ref(zvalue TSRMLS_CC);
                }
                break;
            case IS_RESOURCE:
                {
                    TSRMLS_FETCH();
    
                    /* destroy resource */
                    zend_list_delete(zvalue->value.lval);
                }
                break;
            case IS_LONG:
            case IS_DOUBLE:
            case IS_BOOL:
            case IS_NULL:
            default:
                return;
                break;
        }
    }
    //zend.h
    
    #define STR_FREE_REL(ptr) if (ptr && !IS_INTERNED(ptr)) { efree_rel(ptr); }
    
    
    #define efree_rel(ptr)                            _efree((ptr) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC)
    
    //zend_alloc.c
    
    ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    {
        TSRMLS_FETCH();
    
        if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
            AG(mm_heap)->_free(ptr);
            return;
        }
        _zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    }
    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        char *variable="abc";
        char **variable_ptr_ptr=variable;
    
        char *variable_ptr=*variable_ptr_ptr;
    
        char *value="def";
        char **value_ptr_ptr=value;
        char *value_ptr=*value_ptr_ptr;
    
        *variable_ptr_ptr=value_ptr;
        return 0;                                                                                                                                        
    }
  • 相关阅读:
    Android,资料分享(2015 版)
    Http请求与响应
    SpringMVC + Spring 3.2.14 + Hibernate 3.6.10 集成详解
    ORA-14402: 更新分区关键字列将导致分区的更改
    Android Service的生命周期
    Android Service基础
    Android Intent 基本使用及对象构成
    Sublime Text3 个人使用心得
    深入了解line-height
    overflow之锚点技术实现选项卡
  • 原文地址:https://www.cnblogs.com/taek/p/3834878.html
Copyright © 2011-2022 走看看