PHP底层原理分析(二):写时复制和强制分裂

袁志蒙 次浏览

摘要:学习需要知其然而知其所以然,PHP底层相关就是这类知识,从上文中知道声明一个变量,将会产生一个结构体,那么在传值赋值和引用赋值时, 结构体是如何变化的呢?

从上文(http://blog.yzmcms.com/html/php/173.html) 中知道声明一个变量,将会产生一个结构体,那么在传值赋值和引用赋值时, 结构体是如何变化的呢?

一、变量的传值赋值:

以: $a = 3 ; $b = $a为例,此时并没有再次产生结构体,而是2个变量共用1个结构体,refcount__gc 值为2

$a = 3

此时的结构体:

{
value:3
type:IS_LONG
refcount__gc:1
is_ref__gc:0
}

$b = $a;

此时$a和$b共用一个结构体:

{
value:3
type:IS_LONG
refcount__gc:2
is_ref__gc:0
}

思考: a, b指向同一个结构体, 那么,修改a,或b ,对方会不会受干扰?

答: 不会,

因为两者,有一方修改时,将会造成结构体的分裂。

$b = 5; //此时修改变量的值

结构体如下:

$a的结构体是:

{
value:3
type:IS_LONG
refcount__gc:1
is_ref__gc:0
}

$b的结构体是:

{
value:5
type:IS_LONG
refcount__gc:1
is_ref__gc:0
}

结构体一开始共用,到某一方要修改值时,才分裂。这种特点称为Copy-on-Write,也就是写时复制。

二、变量的引用赋值:

当引用赋值时, 双方共用一个结构体(is_ref__gc=1)

$a = 1;

此时的结构体:

{
value:1
type:IS_LONG
refcount__gc:1
is_ref__gc:0
}

$b = &$a;

此时$a和$b共用一个结构体:

{
value:1
type:IS_LONG
refcount__gc:2
is_ref__gc:1
}

is_ref__gc:1表示引用赋值,此时,如果修改$a和$b任意一个值,结构体不会分裂,$a和$b两个值也将都会修改;

三、强制分裂:

那么现在有这样一个代码:

$a = 3;
$b = $a;
$c = &$a;

$c = 5;
echo $a.$b.$c; //535

为什么会是这样的结果呢,这跟上面我们讲的结构体不一样呢?

原因就是此时发生了强制分裂

当is_ref__gc[引用属性]从0->1,如果refcount__gc>1,那么就会发生强制分裂。

这个就是强制分裂。原本已经经过传值赋值的变量,再次引用赋值出去。被传值赋值的变量就会被分裂出一个结构体,简单可以理解为:在引用变量主动赋值前,该变量传值赋值过,就会发生强制分裂。

上述代码中:

$b强制分裂出一个结构体:

{
value:3
type:IS_LONG
refcount__gc:1
is_ref__gc:0
}

$a个$c共用一个结构体:

{
value:5
type:IS_LONG
refcount__gc:2
is_ref__gc:1
}

注意:在数组中慎用引用赋值,例如:

$arr = array(0,1,2,3);
$x = &$arr[1];
$tem = $arr;
$arr[1] = 999;
echo $tem[1];

//结果为 999
随机新闻

表情

共3条评论