变量赋值(非引用) 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内核的实现(三),布布扣,bubuko.com

时间: 2024-08-02 10:54:02

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

Vim 中的变量赋值、引用与作用域

使用 let 进行变量赋值,echo 打印变量的值, unlet 销毁变量. 对于 Vim 选项还可用 set 来更方便地操作,比如 set {option}, set no{option}, set {option}?. 普通变量可以直接引用,环境变量要加前缀 $.寄存器变量要加前缀 @.Vim 选项要加前缀 &. 变量默认作用域取决于定义的位置,函数内则为函数作用域,外部则为全局变量. 赋值和引用变量时可以使用 b:,g:,l:,t: 等前缀来指定要操作哪个作用域的变量. 和其他编程语言一样

十三、Shell篇——变量赋值、引用、作用范围

变量的定义 变量名的命名规则 - 字母.数字.下划线 - 不以数字开头 变量的赋值 为变量赋值的过程,称为变量替换 变量名=变量值 - a=123 使用let为变量赋值 - let a=10+20 将命令赋值给变量 - l=ls 将命令结果赋值给变量,使用$ () 或者" 变量值有空格等特殊字符可以包含在""或"中 (1)将命令结果赋值给变量,使用$ () 或者" [email protected] ~ % cmd1=`ls test/` [email p

Linux Shell编程变量赋值和引用

我们可以使用任意一种文字编辑器,比如gedit.kedit.emacs.vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行): #!/bin/sh ... 注意:最好使用“!/bin/bash”而不是“!/bin/sh”,如果使用tc shell改为tcsh,其他类似. 符号#!用来告诉系统执行该脚本的程序,本例使用/bin/sh.编辑结束并保存后,如果要执行该脚本,必须先使其可执行: chmod +x filename 此后在该脚本所在目录下,输入 ./filename 即可

PHP变量引用赋值与变量赋值变量的区别

变量默认总是传值赋值.那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量.这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量.有关这种类型的赋值操作,请参阅表达式一章. <?php $foo='abc'; $b=$foo; $b="my name is $b"; echo "$b"; //my name is abc echo "$foo"; // abc PHP

变量赋值和销毁

变量赋值有两种: 1:传值赋值, 先看图:如下 变量名存放处,可以看成一个体,装备 值和类型  又是一个个体, 每个变量名对应着一个值和一个隐属性(类型)  你值改成什么,名不会有影响 .一样,你名改什么,也影响不了别人.  这种赋值,叫传值赋值. 来看代码: $a=23; $b=20; $b=$a; var_dump($a,$b);  //代码分析: 要打印出变量 $a,$b,  其值为?? ,先看$a,值是23, 然后看$b其值是个变量$a,那个计算下,$a值是23,然后23再赋值给$b .

C++函数返回引用、非引用以及临时变量的问题

C++中新增了引用类型,所以函数的返回值可以是引用类型.那么就会有人想问 返回引用类型与返回非引用类型有区别吗? 结论是显然的,而且有明显的区别.尤其初学者会很容易绕进去.让我们先看四个函数原型.以int类型来举例 (1) int fun(...) { return ....//后面跟的是一个引用 } 例如:int fun(int &a) { return a; } (2)int fun(...) { return....//后面跟的是一个非引用 } 例如:int  fun(int a) { r

变量赋值 php内核的实现(一)

<?php $name="abc"; $name="def"; 第二行代码运行后,"abc"去哪里了?明显被内存回收了,不是退回给OS,而是退回了当初分配给PHP的一大块内存区域;第一行中的$name哪儿去了,也被删除了 验证结论: 将常量赋值给某变量,内核会大致进行以下几个步骤: 1:将此变量的refcounf_gc减1 2:将此变量放入GC buffer中,当回收垃圾条件成熟时,回收内存 3:从php启动时已获取的一大片内存中为该变量分

变量赋值 php内核的实现(二)

<?php$a=1;$b=&$a;$c=2;$a=&$c;echo $a."\n";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)如果refcou

java 成员变量、局部变量、静态变量、类变量、非静态变量、实例变量、向前引用、非法向前引用、静态代码块、非静态代码块

①java类的成员变量有俩种: 一种是被static关键字修饰的变量,叫类变量或者静态变量 另一种没有static修饰,为成员变量 ②通俗点说: 类的静态变量在内存中只有一个,java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享.静态变量可以直接通过类名进行访问,其生命周期取决于类的生命周期. 而实例变量取决于类的实例.每创建一个实例,java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中,其生命周期取决于实例的生命周期. 注意点: 1.JAVA中初始化