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;                                                                                                                                        
    }
  • 相关阅读:
    HDU2586 How far away?(tarjan的LCA)
    You Raise Me Up
    POJ2891 Strange Way to Express Integers(中国剩余定理)
    POJ2142 The Balance(扩展欧几里得)
    HDU 1166模仿大牛写的线段树
    NetWord Dinic
    HDU 1754 线段树裸题
    hdu1394 Minimum Inversion Number
    hdu2795 Billboard
    【完全版】线段树
  • 原文地址:https://www.cnblogs.com/taek/p/3834878.html
Copyright © 2011-2022 走看看