30
2017
10

PHP 引用变量

1、引用变量的定义

在PHP 中引用的意思是:不同的名字访问同一个变量内容.使用&表示

使用 & 会使(如$a = &$b)指向同一个内存地址(这并不像 C 的指针:例如你不能对他们做指针运算,他们并不是实际的内存地址),一个发生改变,另一个也会发生改变

2、使用 memory_get_usage() 函数观察内存的变化

2.1、不使用 &

因为PHP 中COW(Copy On  Write) 会导致赋值是引用上一个变量的地址(内存不会发生太大变化),只有在发生 写 操作的时候,才会开辟新的内存地址

$a = range(0,1000);
var_dump(memory_get_usage());

$b = $a;
var_dump(memory_get_usage());

$a = range(0,1000);
var_dump(memory_get_usage());
允许结果:

内存在第一次和第二次并没有太大的差异,第三次产生较大差异

2.2、使用 & 

$a = range(0,1000);
var_dump(memory_get_usage());

$b = &$a;
var_dump(memory_get_usage());

$a = range(0,1000);
var_dump(memory_get_usage());

运行结果:

内存在过程中基本没有发生变化,虽然第三步进行了写操作,但是 $a,$b引用的同一个地址,就不需要开辟新地址

3、使用xdebug 观察

xdebug 的安装方法 网上很多,这里不细讲(php 的一个扩展插件而已)

3.1、不使用 &

//zval 变量容器
$a = range(0, 3);
xdebug_debug_zval('a');

//定义变量b,把a的值赋值给b
$b = $a;
xdebug_debug_zval('a');
//修改a
$a = range(0, 3);
xdebug_debug_zval('a');

运行如下:

refcount用以标识指向这个zval变量容器的变量个数

is_ref(bool),标识此变量是否属于引用集合

第二步只进行了COPY 操作,使$a , $b 指向同一个内存地址, refcount = 2,而第三步 发生了写操作(is_ref=0 不是引用),重新开辟了内存地址,refcount= 1

3.2、使用 &

//zval 变量容器
$a = range(0, 3);
xdebug_debug_zval('a');

//定义变量b,把a的值赋值给b
$b = &$a;
xdebug_debug_zval('a');

//修改a
$a = range(0, 3);
xdebug_debug_zval('a');

运行结果:

采用了 引用(&),所以 从第二步开始 refcount = 2,is_ref = 1(引用) ,引用状态下不开辟新的内存地址;

4、特殊的引用(对象)

php 中 OBJECT 本身就是引用传值(自 PHP 5 起,new 自动返回引用,因此在此使用 =& 已经过时了并且会产生 E_STRICT 级别的消息。

<?php
//对象本身就是引用传递
class Person 
{
	public $name = 'zs';
}
$p1 = new Person;
xdebug_debug_zval('p1');

$p2 = $p1;
xdebug_debug_zval('p1');

$p2->name = 'ls';
xdebug_debug_zval('p1');


运行结果:

OBJECT 赋值情况下 会共享内存地址,但本身又不是引用。

5、unset

<?php
//unset 只会取消引用,不会销毁空间
$a = '';
xdebug_debug_zval('a');
$b = &$a;
xdebug_debug_zval('a');
unset($b);
xdebug_debug_zval('a');

运行结果:

所以在第一步的时候  refcount = 0 

对应 引用(&),unset只会取消引用,而不会销毁内存地址

5、总结

通过对 is_ref 判断是否是引用变量,如果是引用变量,修改时直接修改(原内存地址),否则,则需要进行 分离(重新开辟新地址),而  usset 变量只是取消该变量的引用,而不会消除内存地址,只有当refcount = 0;内存才有可能被回收



« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。