变量的赋值与引用:
注意:
在传值赋值时,
以: $a = 3 ; $b = $a为例,
并没有再次产生结构体,而是2个变量共用1个结构体.
此时,2个变量,指向同1个结构体,
refcount_gc 值为2
思考: a, b指向同一个结构体, 那么,修改a,或b ,对方会不会受干扰?
答: 不会,
因为2者,有一方修改时,将会造成结构体的分裂.
结构体一开始共用, 到某一方要修改值时,才分裂.
这种特点,称为cow , copy on write ,
当引用赋值时, 双方共用一个结构体(is_ref_gc=1)
发生如下图的变化
强制分裂:
$a = 3;
底层结构体如下:
/**
{
value : 3
refcount_gc : 1
is_ref_gc : 0
**/
$b = $a;
/**
value : 3
refcount_gc :2
is_ref_gc : 0
**/
$c = &a;
/**
//如果is_ref_gc 从0->1的过程中,refcount_gc>1时,将会强制分裂
b分裂一份结构体
{
value : 3
refcount_gc : 1
is_ref_gc : 0
}
a,c
{
value : 3
refcount_gc : 2
is_ref_gc : 1
}
**/
引用数组时的怪现象:
$arr = array(0,1,2,3);
$tmp = $arr;
$arr[1] = 11;
echo $tmp[1];//1
//此时$arr和$tmp公用一个哈希表(用来存放数组数据)
图解:
图一:
当$arr初始化时,底层会生成一个哈希表来存放数组里面的值
当执行$tmp = $arr时,$tmp中的zvalue指向了$arr的哈希表
图2:
当执行$arr[1] = 11时,底层进行并没有强制分裂($tmp中下标为1的此时进行了分裂),而是将$tmp的下标为1指向新分裂的结构体, 而 下标为0,2,3都是指向原来$arr哈希表里面的值
$arr = array(0,1,2,3);
$x = &$arr[1];
$tmp = $arr;
$arr[1] = 999;
echo $tmp[1];//999
这是PHP一个BUG,当执行$x = &$arr[1]时,PHP将哈希表中的$arr中的值为1的is_ref_gc修改为1,然后执行$tmp = $arr时,PHP将$tmp直接指向$arr的哈希表(其中包含了地址赋值的内容,这个地方并没有进行分裂)
循环数组时的怪现象:
//引用时的一些怪现象
$arr = array(0,1,2,3);
foreach( $arr as $v) {
}
var_dump(current($arr)); //最后数组指针停留在数组结尾,取不到值,输出false
$arr = array(0,1,2,3);
foreach( $arr as $k => $v) {
$arr[$k] = $v;
}
var_dump(current($arr)); //输出1
注意:$arr跟$arr(copy即foreach中的$arr)的关系是赋值关系
var_dump(current($arr)); //输出1,在foreach循环中,$arr是上面的$arr的一个copy数据,因为当执行foreach的第一步时,PHP读取$arr(copy)数组中的第一个值,然后将指针下移到下一个值中(注意:这里是先读取指针指向的值,然后才将指针移动到下一个地址),然后第一次执行$arr[$k] = $v的赋值操作时,$arr跟$arr(copy)要进行分裂,原来的$arr指针只是移动了一个位置,然后就不移动了
$arr = array(1,2,3);
foreach( $arr as &$v) {
}
//上面的foreach等价于$v = &$arr[2]
foreach ( $arr as $v) {
print_r($arr);
}
输出:
121
122
122
原因:第一个foreach将数组的最后一个元素的地址赋值给$v,然后第二个foreach中,每次循环都将数组最后一个元素的值修改了
提醒:
1.使用数组时,慎用地址引用
2.foreach使用后,不会把数组内部的指针重置,需要使用reset