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)?
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:
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);
?>
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With