PHP引用导致数据损坏

PHP引用导致数据损坏,php,reference,Php,Reference,我正在编写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

我正在编写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);
?>
而不是

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);
?>

当然,复制数据可以解决问题。但是我想了解这个参考的奇怪问题是什么,以及如何避免这些问题。也许在代码中使用PHP引用通常是不好的(就像许多人说的C指针)?

PHP语言的引用机制具有特定的功能,这是其他编程语言所不具备的。人们普遍认为,对象反映了通过任何引用对其属性所做的所有更改。但是对引用本身的赋值是被禁止的,或者使引用指向另一个对象。与此相反,PHP中对引用的赋值将整个底层对象(引用指向的对象)替换为being赋值的对象。所以

$a = 1; $b = 2;
$r = &$a;
$r = $b;
echo $a; // will output '2'
这适用于assigment,但不适用于
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);
}

这对我很有用。。。。如果我知道你想做什么,也许我可以做得不一样。。但这应该是可行的

$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);
}

您在
$extradata
上的循环中再次使用了
$x
,这会导致引用变得不可靠

这项工作:

$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);

  • 不要重复使用变量
  • 避免引用

我已经在我的PHP安装(win64-5.4.7)上确认了相同的行为-我不知道为什么只有
C
消失了。如果您使用
var\u dump
,您将看到
C
出现了
&NULL
。一个奇怪的代码。你想达到什么目标?为什么不先合并数组呢?(
array\u merge()
,)然后运行
array\u map()
()更改大小写。>为什么不先合并数组?最初我尝试附加从MySQL游标获取的值。后来,我简化了代码,将其放入PHPfiddle中,生成了游标数组。@deceze“可能重复”-我已经尝试并看到后续的
foreach
循环对工作正常!但是
While
after
foreach
会导致这种奇怪的行为。循序渐进的解释应该解释发生了什么。您只需考虑分配给引用时会发生什么。无论是第二次
foreach
还是
while
或一个简单的
=
都是无关紧要的。与其说OP想完成什么,不如说OP看到了OP要求解释的奇怪行为。@deceze,回答你的编辑。。。不,我只是因为个人原因语法不好。。但我正在好转:)谢谢!奇怪的语言特征!它在哪里有用?它是通过将变量引用传递给函数来使用的,在函数中它被赋值,变量值也相应地改变。如果没有这样的引用分配规则,您必须将您的值包装到对象中,以便能够通过引用传递它(就像在JS中发生的那样)。为什么“C”被替换为null?因此它被替换为
每个
中的每个值:“d”、“e”、“f”以及最后的null(每次while循环中断后).
PHP引用如果可能的话,您应该根本不使用它们;)
$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);
}
$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);