6

我正在编写 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 指针)?

4

3 回答 3

15

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);
}
于 2013-10-25T15:29:52.257 回答
0

这对我有用....如果我知道您要做什么,也许我可以做不同的事情..但这应该可以。

$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);
}
于 2013-10-25T15:36:53.323 回答
0

$x在循环中再次使用 over $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);

  • 不要重用变量
  • 避免引用
于 2013-10-25T15:40:33.170 回答