PHP reference causes data corruption [duplicate]

时光总嘲笑我的痴心妄想 提交于 2020-01-14 08:48:05

问题


I am writing PHP code to make some transformations of every value in an array, then to add some values to the array from external source (MySQL cursor or, say, another array). If I use foreach and a reference to transform array values

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

(Here it is in PHPfiddle)

than data is beeing corrupted. So I get

Array ( [0]=>A [1]=>B [2]=> [3]=>D [4]=>E [5] =>F )

instead of

Array ( [0]=>A [1]=>B [2]=>C [3]=>D [4]=>E [5] =>F )

When I use no reference and write

foreach( $data as &$x ) 
    $x = strtoupper($x);

transformation does not occur, of course, but data is not corrupted too, so I get

Array ( [0]=>a [1]=>b [2]=>c [3]=>D [4]=>E [5] =>F )

If I write code like this

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

everything works as expected.

Array ( [0]=>A [1]=>B [2]=>C [3]=>D [4]=>E [5] =>F )

Of course, I copying data solves the problem. But I would like to understand what is the strange trouble with that reference and how such troubles can be avoided. Maybe it is generally bad to use PHP references in code (like many people say about C-pointers)?


回答1:


References mechanism of PHP language has specific feature, that is not common to other programming languages. It is commonly accepted that object reflects all changes, made to its properties through any reference to it. But assignment to reference itself is either prohibited or makes the reference point to another object. Instead of this, assignment to reference in PHP substitutes the whole underlying object (object pointed by reference) with the one, beeing assigned. So

$a = 1; $b = 2;
$r = &$a;
$r = $b;
echo $a; // will output '2'

This is true to assigment, but not true to unset call, which will not destroy underlying object, but break the link between the reference and pointed object.

$a = 1; $b = 2;
$r = &$a;
unset($r); //!
$r = $b;
echo $a; // will output '1'

This reference behaviour is useful in some cases, but it is often misunderstood, what leads to problems like shown in question.

To aviod problems with PHP references you should:

  • Unset every reference as early as possible (at the point when it becomes unnecessary).

So, this code will work

<?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);
?>
  • Generally it is considered a bad style to reuse local variable names in several control structures.

So the following code will work too

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



回答2:


You're using $x again in the loop over $extradata, which causes the references to go wonky.

This works:

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

  • Don't reuse variables
  • Avoid references



回答3:


This works for me.... Maybe I could have done it differently if I knew what you were trying to do .. yet this should work.

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


来源:https://stackoverflow.com/questions/19593835/php-reference-causes-data-corruption

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!