PHP基础之引用变量

引用基本概念:用不同的名字访问同一个变量的内容,用符号&表示
php的cow机制:英文名称copy by write,意思是只有进行修改操作才会copy

1、变量直接赋值的情况

<?php
//定义a
$a = range(0,3);
var_dump(memory_get_usage());//查看内存使用情况
xdebug_debug_zval('a');
//引用
$b = $a;
var_dump(memory_get_usage());
xdebug_debug_zval('a');
//修改a
$a = range(0,3);
var_dump(memory_get_usage());
xdebug_debug_zval('a');

运行结果
直接给变量赋值并查看其内存值和zval值

从zval值分析

第一个显示连接数是1,不是引用类型。这个容易理解,此刻只有变量a指向该空间
第二个显示连接数是2,不是引用类型。这里对变量b直接赋值,在没有对变量进行操作前始终是指向同一个空间,如下图
变量a直接赋值给变量a
第三个zval值显示变量a的连接数为1,不是引用类型。此刻的变量a进行了操作,根据php的cow机制a另外开辟了一块空间并指向该空间,故显示连接数为1。如下图
变量a进行操作后新复制一份空间出来

从内存空间占有量分析

很明显,在$a进行操作后内存空间明显增加,即验证(copy on write机制)了 $a对之前的变量空间进行了复制

2、引用变量的情况

我们将前面的赋值操作改为引用,查看下结果

<?php
$a = range(0,100);
var_dump(memory_get_usage());//查看内存使用情况
$b = &$a;//将$a的地址给$b
var_dump(memory_get_usage());
$a = range(0,100);
var_dump(memory_get_usage());

运行结果如下
引用变量情况下的内存情况
可以看见,引用变量后的运行结果内存空间的使用没有明显变大,因为这里使用了引用,引用后的变量永远指向同一个空间地址,如下图
变量b引用了变量a
我们再来看如下代码

<?php
//定义a
$a = range(0,3);
var_dump(memory_get_usage());//查看内存使用情况
xdebug_debug_zval('a');
//引用
$b = &$a;
var_dump(memory_get_usage());
xdebug_debug_zval('a');
//修改a
$a = range(0,3);
var_dump(memory_get_usage());
xdebug_debug_zval('a');

打印结果
打印变量内存结果和zval结果
第一个zval结果显示指向该内存空间中只有一个变量,不是引用类型
第二个zval结果显示指向该内存空间的有两个变量,是引用类型,由代码可知我们确实是让变量b引用变量a
第三个zval结果显示和第二个的一样,即对变量a进行操作后没有进行空间复制,变量a和变量b仍然指向同一块内存空间。(引用的时候其实是拥有该空间的地址)
从内存空间使用中也可看出,在对变量a进行操作后内存空间大小仍是不变。

3、对象的引用

对象本身就是引用传递,即当操作时不会进行对象的复制,要复制可以使用对象的克隆方法。

<?php
class Persosn{
    public $name = '张三';
}
$a = new Persosn();
xdebug_debug_zval('a');

$b = $a;
xdebug_debug_zval('a');

$b->name = '李四';
xdebug_debug_zval('a');

运行结果
在这里插入图片描述
因为对象本身就是引用传递,故内存中并没有再复制一份出来,连接数依然是2

4、真题

<?php
/*
 * 写出如下程序的输出结果
 * */
$data = ['a','b','c'];
foreach ($data as $key=>$val){
    $val = &$data[$key];
    var_dump($data);
}
var_dump($data);
/*
 * 程序运行时,每一次循环结束后变量$data的值是什么?请解释
 * 程序执行完成后,变量$data的值是什么?请解释
 * */

运行结果
在这里插入图片描述
第一次循环的时候,$ key=0,$val=a,循环体内 $val 指向 $data[0]的内存空间,故此时循环结果为a,b,c
第二次循环的时候, $ key=1, $val=b,由于 $val指向 $data[0]的内存空间,故此时 $data[0]的值变为b,则输出 $data的值为b,b,c,此时循环体内 $val指向的内存空间为 $ data[1]
第三次循环的也一样, $ key = 2, $val=c,由于 $ val 指向 $ data[1]的内存空间,则此时 $data[1]的值变为c,故输出结 $data的值为b,c,c,此刻 $val指向 $data[2]

因此最终结果为b,c,c

扩展

zval()

php变量的值存在于一个叫‘zval’的容器中,zval包含了该变量的类型和值,还包含两个字节的额外信息。
第一个是“is_ref”,是一个bool值,用来标识这个变量是否是属于引用集合。通过这个字节php引擎能够把普通变量和引用变量区分开,由于php允许用户通过使用&来使用自定义引用,zval变量容器中还有一个内部引用计数机制来优化内存使用。
第二个额外字节是“refcount”,用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。所有的符号存在一个符号表中,期中每个符号都有作用域(scope),那些脚本(比如:通过浏览器请求的脚本)和每个函数或者方法也都有作用域。当一个变量被赋常量值时,就会生成一个zval变量容器。

unset()

只会取消引用,不会销毁内存空间

<?php
$a = 1;
$b = &$a;
unset($b);
var_dump($a);

输出结果
在这里插入图片描述
变量b对变量a进行引用,此刻指向同一块内存空间,因为unset()只会取消引用不会销毁内存空间,故此刻a的值任然为1,如下图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值