您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
2-1 PHP引用变量考察点 (上)
发布时间:2020-10-01 16:31:46编辑:雪饮阅读()
Range
首先介绍下php中range函数,range函数可以允许输入一个数值范围,然后依据该范围建立一个数组。如:
<?php
function myDump($val){
echo "<pre>";
print_r($val);
echo "</pre>";
}
$a=range(0,10);
myDump($a);
?>
其运行效果如:
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
[8] => 8
[9] => 9
[10] => 10
)
COW(copy on write)
一般的,变量存在COW机制,即当一个变量定义且有值的情况下将该变量赋值给另外一个新的变量,此时这两个变量是共用同一个内存空间中同一个堆,而当此时”原来”变量被赋予新值的时候则内存空间中会复制堆(write的操作),这就是所谓的copy on write。那么示意图如:
memory_get_usage
memory_get_usage函数可以获取运行时程序内存情况,如:
<?php
function myDump($val){
echo "<pre>";
print_r($val);
echo "</pre>";
}
$a=range(0,10);
myDump(memory_get_usage());
?>
运行效果如:
404104
COW机制的验证
上面我们提到了COW机制,但是空口无凭,然而我们也介绍了memory_get_usage则我们可以利用memory_get_usage来验证我们的理论。
<?php
function myDump($val){
echo "<pre>";
print_r($val);
echo "</pre>";
}
$a=range(0,10);
myDump(memory_get_usage());
//COW copy on write
$b=$a;
myDump(memory_get_usage());
$a=range(0,5);
myDump(memory_get_usage());
?>
运行效果如:
405432
405432
405808
根据运行结果的3次内存情况比较不难证实我们结论的可靠性。
发散思维到对象
我们上面了解了COW机制,我们是基于数组的,那么此机制对于我们最认可的“对象”是否也有同样的机制。
<?php
function myDump($val){
echo "<pre>";
print_r($val);
echo "</pre>";
}
class ab{
public $name="ab";
}
class ab1{
public $name="ab1";
}
$a=new ab();
myDump(memory_get_usage());
//COW copy on write
$b=$a;
myDump(memory_get_usage());
$a=new ab1();
myDump(memory_get_usage());
myDump($a);
myDump($b);
?>
运行结果:
406256
406256
406312
ab1 Object
(
[name] => ab1
)
ab Object
(
[name] => ab
)
根据运行结果可知“对象”同样吃这一套。
xdebug_debug_zval
xdebug_debug_zval函数可以查看某个变量的内部结构。一般的该函数默认是没有被开启的,他来自于xdebug扩展,所以需要开启该扩展才可以使用。那么开启该扩展如:
那么该函数获取某个变量的内部结构如:
<?php
function myDump($val){
echo "<pre>";
print_r($val);
echo "</pre>";
}
$a=range(0,3);
myDump(xdebug_debug_zval('a'));
运行结果:
a: (refcount=1, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2, 3 => (refcount=0, is_ref=0)=3)
运行结果中我们需要注意的是refcount和is_ref这两个分别指的是该变量引用次数和该变量是否引用变量。
结合xdebug_debug_zval我们再来总结下COW机制
<?php
function myDump($val){
echo "<pre>";
print_r($val);
echo "</pre>";
}
$a=range(0,3);
myDump(xdebug_debug_zval('a'));
$b=$a;
myDump(xdebug_debug_zval('a'));
$a=range(0,3);
myDump(xdebug_debug_zval('a'));
运行效果如:
a: (refcount=1, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2, 3 => (refcount=0, is_ref=0)=3)
a: (refcount=2, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2, 3 => (refcount=0, is_ref=0)=3)
a: (refcount=1, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2, 3 => (refcount=0, is_ref=0)=3)
从该运行结果中我们可以看到第一次定义变量a时其引用统计为1,因为只有它自己,而第二次将它赋值给新变量b时则它算是被b引用了一次,所以此时它的引用统计变量2了,那么当第三次变量a被重新赋值后,则开辟了新的堆,此时变量a与b彼此孤立,所以变量a的引用统计再次恢复到了1.
&
&符号在php中可以使得一个变量变成引用变量(引用赋值),即地址共享。
比如上面例子中$b=$a之后$a重新赋值后变量a与b就孤立了,那么如果用&来赋值则会使得a与b共享同样的地址,无论a与b谁被修改,另外一个的值同样会等于修改后的新值。
如:
<?php
function myDump($val){
echo "<pre>";
print_r($val);
echo "</pre>";
}
$a=range(0,3);
myDump(xdebug_debug_zval('a'));
$b=&$a;
myDump(xdebug_debug_zval('a'));
$a=range(0,3);
myDump(xdebug_debug_zval('a'));
myDump($a);
myDump($b);
运行结果:
a: (refcount=1, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2, 3 => (refcount=0, is_ref=0)=3)
a: (refcount=2, is_ref=1)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2, 3 => (refcount=0, is_ref=0)=3)
a: (refcount=2, is_ref=1)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2, 3 => (refcount=0, is_ref=0)=3)
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
)
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
)
从运行结果中可以看到第二次开始引用统计和前面例子一样,但第二次开始变量a已经是引用变量了(is_ref=1),那么第三次变量a的引用统计不变,是因为引用变量地址共享并没有因为变量a重新赋值而导致变量b成为孤岛,那么第三次变量a仍旧是引用变量,这个自然是没有什么可说的,除非断掉引用。
关键字词:Range,php,COW,copy on write,memory_get_usage,xdebug_debug_zval,&
上一篇:马哥docker学习笔记