PHP的变量_数组_对象值复制和引用复制

一.变量
1.变量传值赋值
在PHP两个变量之间进行传值赋值时,不会产生新结构体,而是2个变量共用1个结构体(refcount__gc=2),
只有在1个变量改变时,将会造成结构体的分裂;

$a=10;
/* $a结构体 {
    value: {long 10}
    type: IS_LONG
    recount_gc : 1
    is_ref_gc :0
}*/
$b=$a;
/* $a $b结构体   {
    value: {long 10}
    type: IS_LONG
    recount_gc : 2
    is_ref_gc :0
}*/
$b=5;
/*  $a结构体   {
    value: {long 10}
    type: IS_LONG
    recount_gc : 1
    is_ref_gc :0
}
$b结构体   {
    value: {long 5}
    type: IS_LONG
    recount_gc : 1
    is_ref_gc :0
}*/

结构体一开始共用, 到某一方要修改值时才分裂. 这种特点,称为cow , copy on write写时复制

2.变量引用赋值
两个变量之间进行引用赋值时,2个变量共用1个结构体(is_ref_gc=1),

$a=10;
/* $a结构体{
    value: {long 10}
    type: IS_LONG
    recount_gc : 1
    is_ref_gc :0
}*/
$b=&$a;
/* $a $b结构体{
    value: {long 10}
    type: IS_LONG
    recount_gc : 2
    is_ref_gc :1
}*/
$b=5;
/* $a $b结构体{
    value: {long 5}
    type: IS_LONG
    recount_gc : 2
    is_ref_gc :1
}*/

在1个变量改变时,结构体不会分裂,而是直接改值,所有指向此结构体的变量值都变化。

二.数组
一个整体数组的传值赋值和引用赋值可以看成是将多个(数组元素)变量一起赋值。
数组单个的传值赋值和引用赋值可以看成是将一个(数组元素)变量赋值。

$arr=array('a','b','c');
$x=&$arr[1];
$tmp=$arr;
$arr[1]='d';
$arr[2]='e';
var_dump($arr,$tmp);//$arr=array('a','d','e') $tmp=array('a','d','c')

1.数组传值赋值
调用函数时通过将PHP数组作为实参赋给形参,在函数中修改,并不会影响到数组本身。

$arr = array( 
'name' => 'corn', 
'age' => 24
); 
test_arr($arr); 
function test_arr($arr){ 
$arr['name'] = 'xiaoming'; 
} 
print_r($arr); //result: Array ( [name] => corn [age] => 24 ) 

说明此过程中的传递为值传递,数组变量并非是指向此数组本身的引用,
PHP数组本身以值的形式存在,形参只是是对数组元素数据的拷贝。

$arr=array('a','b','c');
/* $arr结构体{
    value: *ht-->指向哈希表{'a','b','c'}
    type: IS_ARRAY
    recount_gc : 1
    is_ref_gc :0
}*/
$tmp=$arr;//传值引用 recount_gc : 2
/* $arr $tmp结构体{
    value: *ht-->指向哈希表{'a','b','c'}
    type: IS_ARRAY
    recount_gc : 2
    is_ref_gc :0
}*/
$arr[1]='e';//根据cow机制,开始复制数组,结构体分裂
/* $arr结构体{
    value: *ht-->指向哈希表{'a','e','c'}
    type: IS_ARRAY
    recount_gc : 1
    is_ref_gc :0
}
$tmp结构体{
    value: *ht-->指向哈希表{'a','b','c'}
    type: IS_ARRAY
    recount_gc : 1
    is_ref_gc :0
}*/

2.数组引用赋值

$tmp=&$arr;//复制引用 recount_gc : 2
/* $arr $tmp结构体{
    value: *ht-->指向哈希表{'a','b','c'}
    type: IS_ARRAY
    recount_gc : 2
    is_ref_gc :1
}*/
$arr[1]='e';//结构体不会分裂,而是直接改值,所有指向此结构体的变量值都变化
/* $arr结构体{
    value: *ht-->指向哈希表{'a','e','c'}
    type: IS_ARRAY
    recount_gc : 2
    is_ref_gc :1
}

3.数组foreach($items as $item)
//在PHP中 next、current、prev、end、reset等函数和数组元素值修改的行为会对数组进行拷贝操作
数组指针会在新复制的数组上移动,原数组指针在拷贝时就停止移动。eg:

$arr=array('a','b','c','d');
$i=0;
foreach ($arr as $v) {
    if($i==0){
        current($arr);
    }
    $i++;
}
var_dump(current($arr));//返回b

4.数组foreach($items as &$item)
在使用foreach($items as &$item)时,会直接在原数组上进行操作,整个数组相当于多个变量的都使用引用传值。

下面是针对使用PHP数组问题的两个建议:
a)foreach循环内部禁用next、current、prev、end、reset五个array内部指针操作函数,
使用foreach后数组指针不会重置,每个foreach内第一次会重置,可以在foreach后使用reset重置指针。
b)在foreach内部可能有对$items进行的写操作时,推荐使用foreach($items as &$item),避免大数组拷贝。

三.对象

class myclass{
            public $name='lily';
            public $age=5;
        }
        $stu1=new myclass();//$stu1不是对象,只是对象的引用
        /* $stu1结构体{
            value: {handle:2385}-->handle指向哈希表{name:'lily',age:5}
            type: IS_OBJECT
            recount_gc : 1
            is_ref_gc :0
        }*/

1.对象直接赋值
直接赋值只是拷贝对象标识符handle,对象标识符handle的数据指向并没有改变。

    $stu2=$stu1;//recount_gc:2
    $stu2->name='hale';//通过拷贝对象标识符handle指向哈希表修改name值,不会导致结构体分裂
    var_dump($stu1->name,$stu2->name);//hale hale
    $stu2=false;//cow导致结构体分裂,$stu1结构体值不变,recount_gc :0
    /* $stu2结构体{
        value: 0
        type: IS_BOOL
        recount_gc : 0
        is_ref_gc :0
    }*/
    var_dump($stu1->name);//hale

2.对象引用赋值
引用赋值共用一个对象标识符handle,不复制handle

$stu2=&$stu1;
$stu2="abc";//$stu2改变成字符串,handle则不存在了
/* $stu1 $stu2结构体{
    {
        char: 'abc'
        len:3
    }
    type: IS_STRING
    recount_gc : 2
    is_ref_gc :1
}*/

3.对象克隆拷贝
克隆拷贝会形成新的不同对象标识符handle,
这就意味着指向的数据块也是不用的,那么两对象之间的修改操作互不影响了

$stu2=clone $stu1;

标签: php

相关文章

添加新评论