PHP中变量的作用域不像java, c中的那样有明确的限定。比如, 我们在一个php文件中有这样一段代码:
$data = ['a', 'b', 'c'];
//在foreach循环中建立了变量$key和$value
foreach ($data as $key => $value) {
//do nothing here
}
//在foreach外面仍然可以访问这两个变量
var_dump($key);
var_dump($value);
在这个foreach
循环中定义的变量$key
和$value
, 在foreach
外面也是可以访问的。上面代码的执行结果是:
int(2)
string(1) "c"
当然,如果这个foreach是在一个function内,那么在这个function外是不能直接访问这两个变量的。
例子
例1
看下面这个例子:
$data = ['a', 'b', 'c'];
foreach ($data as $key => $value) {
$value = &$data[$key];//引用
}
print_r($data);
执行的结果是:
Array
(
[0] => b
[1] => c
[2] => c
)
我们可以看到变量$data
的值已经被改变了! 这很奇怪吧! 我们在循环中打印变量:
$data = ['a', 'b', 'c'];
foreach ($data as $key => $value) {
$value = &$data[$key];//引用
echo $key, ': ', $value, ' => ', json_encode($data) . PHP_EOL;
}
执行结果是:
0: a => ["a","b","c"]
1: b => ["b","b","c"]
2: c => ["b","c","c"]
我们可以看到:
- 第一次循环时
- 先把
$data[0]
赋给了变量$value
- 随后又将变量
$value
变成了地址引用,指向$data[0]
- 先把
- 第二次循环时
- 先把
$data[1]
赋给了变量$value
,但是因为变量$value
是指向$data[0]
的,这导致$data[0]
的值被修改为 b - 随后又将
$value
指向了$data[1]
的地址
- 先把
- 第三次循环时
- 先把
$data[2]
赋给了变量$value
,但是因为变量$value
是指向$data[1]
的,这导致$data[1]
的值被修改为 c - 随后又将
$value
指向了$data[2]
的地址
- 先把
如果在这个代码后面再修改一下$value
的值, 数组$data
会变成什么样呢?
$data = ['a', 'b', 'c'];
foreach ($data as $key => $value) {
$value = &$data[$key];//引用
echo $key, ': ', $value, ' => ', json_encode($data) . PHP_EOL;
}
foreach ($data as $key => $value) {
}
print_r($data);
//在这里修改$value的值, 然后在看看原来的数组变成了什么
$value = 120;
echo $value . PHP_EOL;
print_r($data);
执行结果是:
0: a => ["a","b","c"]
1: b => ["b","b","c"]
2: c => ["b","c","c"]
Array
(
[0] => b
[1] => c
[2] => c
)
120
Array
(
[0] => b
[1] => c
[2] => 120
)
我们可以看到, $data[2]
的值变成了120,而这可能不是我们想要的!
例2
这是例子是参考手册上的:
$arr = [1, 2, 3, 4];
foreach ($arr as &$value) {
$value = $value * 2;
}
echo '$arr 现在是 ' . json_encode($arr) . PHP_EOL;
// $arr 现在是 [2, 4, 6, 8]
// 前面没有unset掉, 所以这里 $value 仍然指向 $arr[3] 的地址
foreach ($arr as $key => $value) {
// $arr[3] 的值会在每一次循环时被修改
echo $key . ' => ' . $value . ' $arr 现在是 ' . json_encode($arr) . PHP_EOL;
}
执行结果是:
$arr 现在是 [2,4,6,8]
0 => 2 $arr 现在是 [2,4,6,2]
1 => 4 $arr 现在是 [2,4,6,4]
2 => 6 $arr 现在是 [2,4,6,6]
3 => 6 $arr 现在是 [2,4,6,6]
如何避免地址引用带来的问题?
- 用
unset()
来destroy掉变量 - 不用地址引用