我正在编写PHP代码来对数组中的每个值进行一些转换,然后从外部源(MySQL游标或另一个数组)向数组添加一些值。如果我使用 foreach
和引用来转换数组值
<?php
$data = array('a','b','c');
foreach( $data as &$x )
$x = strtoupper($x);
$extradata = array('d','e','f');
// actually it was MySQL cursor
while( list($i,$x) = each($extradata) ) {
$data[] = strtoupper($x);
}
print_r($data);
?>
(这里是PHPfiddle)
比数据正在损坏。所以我得到
Array ( [0]=>A [1]=>B [2]=> [3]=>D [4]=>E [5] =>F )
而不是
Array ( [0]=>A [1]=>B [2]=>C [3]=>D [4]=>E [5] =>F )
当我不使用引用并写入时
foreach( $data as &$x )
$x = strtoupper($x);
当然,转换不会发生,但数据也没有损坏,所以我得到
Array ( [0]=>a [1]=>b [2]=>c [3]=>D [4]=>E [5] =>F )
如果我写这样的代码
<?php
$result = array();
$data1 = array('a','b','c');
foreach( $data1 as $x )
$result[] = strtoupper($x);
$data2 = array('d','e','f');
// actually it was MySQL cursor
while( list($i,$x) = each($data2) ) {
$result[] = strtoupper($x);
}
print_r($result);
?>
一切都按预期工作。
Array ( [0]=>A [1]=>B [2]=>C [3]=>D [4]=>E [5] =>F )
当然,我复制数据可以解决问题。但我想了解这种参考的奇怪问题是什么,以及如何避免这种麻烦。也许在代码中使用PHP引用通常是不好的(就像许多人说的C指针一样)?
PHP语言的引用机制具有特定的功能,这是其他编程语言所不共有的。人们普遍认为,对象反映了通过对它的任何引用对其属性所做的所有更改。但是,要么禁止将引用本身分配给引用,要么使引用指向另一个对象。取而代之的是,PHP 中的赋值引用将整个底层对象(引用指向的对象)替换为分配的对象。所以
$a = 1; $b = 2;
$r = &$a;
$r = $b;
echo $a; // will output '2'
这适用于同意识,但不适用于unset
调用,它不会破坏底层对象,但会断开引用和指向对象之间的链接。
$a = 1; $b = 2;
$r = &$a;
unset($r); //!
$r = $b;
echo $a; // will output '1'
这种参考行为在某些情况下很有用,但它经常被误解,这会导致类似所讨论的问题。
要解决 PHP 引用的问题,您应该:
- 尽早取消设置每个引用(在不需要时)。
所以,这段代码会起作用
<?php
$data = array('a','b','c');
foreach( $data as &$x )
$x = strtoupper($x);
unset($x);
$extradata = array('d','e','f');
// actually it was MySQL cursor
while( list($i,$x) = each($extradata) ) {
$data[] = strtoupper($x);
}
print_r($data);
?>
- 通常,在多个控制结构中重用局部变量名称被认为是一种糟糕的样式。
所以下面的代码也可以工作
<?php
$data = array('a','b','c');
foreach( $data as &$x )
$x = strtoupper($x);
$extradata = array('d','e','f');
// actually it was MySQL cursor
while( list($i,$y) = each($extradata) ) {
$data[] = strtoupper($y);
}
你在循环中再次使用$x
$extradata
,这会导致引用变得不稳定。
这有效:
$data = array('a','b','c');
foreach( $data as &$x )
$x = strtoupper($x);
$extradata = array('d','e','f');
// actually it was MySQL cursor
while( list($i,$anything_but_x) = each($extradata) ) {
$data[] = strtoupper($anything_but_x);
}
print_r($data);
- 不要重复使用变量
- 避免引用
这对
我有用....如果我知道你想做什么,也许我可以以不同的方式做......然而,这应该有效。
$data = array('a','b','c');
foreach( $data as &$x )
$x = strtoupper($x);
$extradata = array('d','e','f');
// actually it was MySQL cursor
foreach ($extradata as &$x) {
$data[] = strtoupper ($x);
}