一、问题
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
的值。