PHP foreach使用 引用& 的坑

一、问题

1、代码

public function test() {
    //产品数据
    $productList = [
        ['id' => 1, 'name' => '产品1', 'status' => 1],
        ['id' => 2,'name' => '产品2', 'status' => 0],
    ];
    foreach ($productList as &$value) {
        $value['desc'] = "产品描述";
    }

    //类型数据
    $typeList = [
        ['id' => 1, 'name' => '普通用户'],
        ['id' => 2, 'name' => 'VIP用户']
    ];
    foreach ($typeList as $value) {
        //TODO...
    }

    var_export($productList);
}

2、希望打印以下值:

array (
  0 => 
  array (
    'id' => 1,
    'name' => '产品1',
    'status' => 1,
    'desc' => '产品描述',
  ),
  1 => 
  array (
    'id' => 2,
    'name' => '产品2',
    'status' => 0,
    'desc' => '产品描述',
  ),
)

3、结果打印以下值:

  • 很明显,$productList的数据是不对的
array (
  0 => 
  array (
    'id' => 1,
    'name' => '产品1',
    'status' => 1,
    'desc' => '产品描述',
  ),
  1 => 
  array (
    'id' => 2,
    'name' => 'VIP用户',
  ),
)

二、解决

1、在foreach循环外unset引用中的$value(推荐)

  • 推荐这种方法
//在foreach循环外unset引用中的$value
public function method1() {
    //产品数据
    $productList = [
        ['id' => 1, 'name' => '产品1', 'status' => 1],
        ['id' => 2,'name' => '产品2', 'status' => 0],
    ];
    foreach ($productList as &$value) {
        $value['desc'] = "产品描述";
    }
    unset($value);

    //类型数据
    $typeList = [
        ['id' => 1, 'name' => '普通用户'],
        ['id' => 2, 'name' => 'VIP用户']
    ];
    foreach ($typeList as $value) {
        //TODO...
    }

    var_export($productList);
}

2、引用后面的foreach中不再重复使用$value变量,改为其他变量

  • 引用后面的foreach中不再重复使用$value变量,改为其他变量(比如$item
//引用后面的foreach中不再重复使用$value变量,改为其他变量(比如$item)
public function method2() {
    //产品数据
    $productList = [
        ['id' => 1, 'name' => '产品1', 'status' => 1],
        ['id' => 2,'name' => '产品2', 'status' => 0],
    ];
    foreach ($productList as &$value) {
        $value['desc'] = "产品描述";
    }

    //类型数据
    $typeList = [
        ['id' => 1, 'name' => '普通用户'],
        ['id' => 2, 'name' => 'VIP用户']
    ];
    foreach ($typeList as $item) {
        //TODO...
    }

    var_export($productList);
}

三、原因分析

详见手册:http://php.net/manual/zh/control-structures.foreach.php

可以很容易地通过在$value 之前加上 & 来修改数组的元素。此方法将以引用赋值而不是拷贝一个值。

<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // 最后取消掉引用
?>

Warning
数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁。否则你会遇到下面的情况:


<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
}
// 现在 $arr 是 array(2, 4, 6, 8)

// 未使用 unset($value) 时,$value 仍然引用到最后一项 $arr[3]

foreach ($arr as $key => $value) {
    // $arr[3] 会被 $arr 的每一项值更新掉…
    echo "{$key} => {$value} ";
    print_r($arr);
}
// ...until ultimately the second-to-last value is copied onto the last value

// output:
// 0 => 2 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 2 )
// 1 => 4 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 4 )
// 2 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
// 3 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
?>

  • foreach 中使用&引用后,当foreach结束后,$value$typeList[count($typeList) - 1]指向相同的内存地址。
  • 因此,修改$typeList中最后一个$value的值也会改变了$productList最后一个$value的值。
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值