PHP引用的坑

研发场景:

写代码时,某一个变量值前后不一致。中间逻辑也没有对该变量重新赋值修改,是什么原因引起的呢?


问题描述:

我们经常接手一些项目功能的二次开发或新代码开发。有时候代码不规范、冗余,常常是一个函数在idea中就要好几屏的显示。

这时候碰到一个需要的变量 $data,在第一屏的时候是某一个值,中间一堆的 new()类处理、foreach() 循环处理...。终于到了第N屏,$data再次被调用。离奇的是 $data值前后不一致了,不可重复读了。

接下来我们开始排查是什么问题引起的这个bug,代码演示↓↓↓。

<?php

function foo(&$arr){
    foreach ($arr as $key => $value){
        if($key === 0){
            $arr[$key] = 'watermelon';
        }
    }
    //逻辑处理...
    return $arr;
}

$data = ['apple','banana','tangerine'];

//各种逻辑判断...
//各种逻辑判断...
//各种逻辑判断...

$result = foo($data); 
//print_r($data);exit();

//各种逻辑判断...
//各种逻辑判断...
//各种逻辑判断...

//$data = test2($data);

//此时将$data作为参数传递给另一个函数
(new fruit)->putOnShelf($data);


class fruit{

    public function putOnShelf($data)
    {
        print_r($data);
    }

}

可以看到,$data 初始变量值是一个数组 $data = ['apple','banana','tangerine']。

中间一堆逻辑处理...

到了 foo()函数,被程序猿A使用引用  “&”。并对新数组 “$arr” 进行了修改,注意此时并没有对 $data 有过重新赋值的处理。

中间一堆逻辑处理...

到了 fruit类,再次使用 $data变量时,来看下此时 $data的值有没有变化。

key为0的值被修改了!!


原因分析:

PHP引用变量指向同一个内存地址,修改引用变量,原变量也会受影响

我们通过 memory_get_usage() 函数分析下变量和内存的关系.

不使用引用变量分析:

<?php

$a = range(1, 100);
echo memory_get_usage();echo PHP_EOL;

//unset($a);
$b = $a;
echo memory_get_usage();echo PHP_EOL;

$b = range(1, 100);
echo memory_get_usage();echo PHP_EOL;


 

 $a初始变量内存 ≈ $a赋值给$b内存 (忽略memory_get_usage函数本身会占一定内存)

$a重新声明值时,内存明显变大

这是因为PHP中存在 COW(Copy On Write)机制,$b 变量不会再开辟一个空间,只会指向 $a的内存地址。当 $b值重新变化时,$b开辟了一个新的内存空间;

使用引用变量分析:

<?php

$a = range(1, 100);
echo memory_get_usage();echo PHP_EOL;

//unset($a);
$b = &$a;
echo memory_get_usage();echo PHP_EOL;

$b = range(1, 100);
echo memory_get_usage();echo PHP_EOL;


 

 $a 初始变量内存 ≈ $b引用$a内存 (忽略memory_get_usage函数本身会占一定内存)

 $b重新声明值时,内存没变化!

也就是说,使用引用变量,$b 和 $a使用相同的指针指向同一个内存空间。$b 值变化时,没有开辟新的内存空间,而是在原内存上更改值。这也解释了修改 $b的值,$a值也跟着变化的问题。

还可以使用 xdebug_debug_zval() 函数进一步分析

<?php

$a = 1;
xdebug_debug_zval('a');
$b = &$a;
xdebug_debug_zval('b');
//unset($a);
$b = 2;
xdebug_debug_zval('b');
xdebug_debug_zval('a');

更直接的分析 $b引用变量 $a,修改 $b的值,影响 $a值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值