我对PHP以及指针和变量的使用有疑问。
以下代码会产生一些我不想要的东西:
<?php
$numbers = array('zero', 'one', 'two', 'three');
foreach($numbers as &$number)
{
$number = strtoupper($number);
}
print_r($numbers);
$texts = array();
foreach($numbers as $number)
{
$texts[] = $number;
}
print_r($texts);
?>
输出如下
Array
(
[0] => ZERO
[1] => ONE
[2] => TWO
[3] => THREE
)
Array
(
[0] => ZERO
[1] => ONE
[2] => TWO
[3] => TWO
)
注意'TWO'在第二个数组中出现两次。
似乎两个foreach循环之间存在冲突,每个循环都声明一个$ number变量(一次是引用,另一次是值)。
但为什么呢?为什么它只影响第二个foreach中的最后一个元素?
答案 0 :(得分:4)
关键是PHP没有指针。它有references,这是一个相似但不同的概念,并且有一些细微的差别。
如果您使用var_dump()而不是print_r(),则更容易发现:
$collection = array(
'First',
'Second',
'Third',
);
foreach($collection as &$item){
echo $item . PHP_EOL;
}
var_dump($collection);
foreach($collection as $item){
var_dump($collection);
echo $item . PHP_EOL;
}
...打印:
First
Second
Third
array(3) {
[0]=>
string(5) "First"
[1]=>
string(6) "Second"
[2]=>
&string(5) "Third"
}
array(3) {
[0]=>
string(5) "First"
[1]=>
string(6) "Second"
[2]=>
&string(5) "First"
}
First
array(3) {
[0]=>
string(5) "First"
[1]=>
string(6) "Second"
[2]=>
&string(6) "Second"
}
Second
array(3) {
[0]=>
string(5) "First"
[1]=>
string(6) "Second"
[2]=>
&string(6) "Second"
}
Second
请注意最后一个数组项中留下的&
符号。
总而言之,无论何时在循环中使用引用,最好在最后删除它们:
<?php
$collection = array(
'First',
'Second',
'Third',
);
foreach($collection as &$item){
echo $item . PHP_EOL;
}
unset($item);
var_dump($collection);
foreach($collection as $item){
var_dump($collection);
echo $item . PHP_EOL;
}
unset($item);
...每次打印预期结果。
答案 1 :(得分:2)
变量$number
即使在循环后也会被初始化,您需要通过unset
此代码正常运行:
<?php
$numbers = array('zero', 'one', 'two', 'three');
foreach($numbers as &$number)
{
$number = strtoupper($number);
}
print_r($numbers);
unset($number);
$texts = array();
foreach($numbers as $number)
{
$texts[] = $number;
}
print_r($texts);
?>
http://www.php.net/manual/en/language.references.unset.php
取消设置引用时,只需断开变量名和变量内容之间的绑定即可。这并不意味着可变内容将被销毁。
...认为这与Unix unlink调用类似。
http://uk.php.net/manual/en/control-structures.foreach.php
关于foreach的警告
即使在foreach循环之后,$ value和最后一个数组元素的引用仍然存在。建议通过unset()来销毁它。
答案 2 :(得分:2)
你应该在第一次循环后打破引用。
foreach($numbers as &$number)
{
$number = strtoupper($number);
}
unset($number);
如documentation中所述:
警告引用$ value和最后一个数组元素 甚至在foreach循环之后。建议将其销毁 未设置()。
另外,如果你使用var_dump()而不是print_r(),你会注意到第一个循环之后的数组的最后一个元素是一个引用:
array(4) {
[0]=>
string(4) "ZERO"
[1]=>
string(3) "ONE"
[2]=>
string(3) "TWO"
[3]=>
&string(5) "THREE"
}
如果你关注Stefan Gehrig关于问题的评论,有一个链接可以完美地解释这种行为: http://schlueters.de/blog/archives/141-References-and-foreach.html