9

I have a question about PHP and the use of pointers and variables.

The following code produces something I wouldn't have expected:

<?php
$numbers = array('zero', 'one', 'two', 'three');

foreach($numbers as &$number)
{
  $number = strtoupper($number);
}

print_r($numbers);

$texts = array();
foreach($numbers as $number)
{
  $texts[] = $number;
}

print_r($texts);
?>

The output is the following

Array
(
    [0] => ZERO
    [1] => ONE
    [2] => TWO
    [3] => THREE
)
Array
(
    [0] => ZERO
    [1] => ONE
    [2] => TWO
    [3] => TWO
)

Notice the 'TWO' appearing twice in the second array.

It seems that there is a conflict between the two foreach loops, each declaring a $number variable (once by reference and the second by value).

But why ? And why does it affect only the last element in the second foreach ?

2

3 Answers 3

4

The key point is that PHP does not have pointers. It has references, which is a similar but different concept, and there are some subtle differences.

If you use var_dump() instead of print_r(), it's easier to spot:

$collection = array(
    'First',
    'Second',
    'Third',
);

foreach($collection as &$item){
    echo $item . PHP_EOL;
}

var_dump($collection);

foreach($collection as $item){
    var_dump($collection);
    echo $item . PHP_EOL;
}

... prints:

First
Second
Third
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(5) "Third"
}
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(5) "First"
}
First
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(6) "Second"
}
Second
array(3) {
  [0]=>
  string(5) "First"
  [1]=>
  string(6) "Second"
  [2]=>
  &string(6) "Second"
}
Second

Please note the & symbol that's left in the last array item.

To sum up, whenever you use references in a loop, it's good practice to remove them at the end:

<?php

$collection = array(
    'First',
    'Second',
    'Third',
);

foreach($collection as &$item){
    echo $item . PHP_EOL;
}
unset($item);

var_dump($collection);

foreach($collection as $item){
    var_dump($collection);
    echo $item . PHP_EOL;
}
unset($item);

... prints the expected result every time.

Sign up to request clarification or add additional context in comments.

Comments

2

variable $number is initialized even after loop , you need to break the reference by unset

this code works properly:

<?php
$numbers = array('zero', 'one', 'two', 'three');

foreach($numbers as &$number)
{
  $number = strtoupper($number);
}

print_r($numbers);
unset($number);

$texts = array();
foreach($numbers as $number)
{
  $texts[] = $number;
}

print_r($texts);
?>

http://www.php.net/manual/en/language.references.unset.php

When you unset the reference, you just break the binding between variable name and variable content. This does not mean that variable content will be destroyed.

...think about this as analogous to the Unix unlink call.

http://uk.php.net/manual/en/control-structures.foreach.php

Warning about foreach

Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().

Comments

2

You should break the reference after the first loop.

foreach($numbers as &$number)
{
   $number = strtoupper($number);
}    
unset($number);

as stated in documentation:

Warning Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().

Also, if you use var_dump() instead of print_r(), you'll notice that the last element of array after the first loop is a reference:

array(4) {
[0]=>
string(4) "ZERO"
[1]=>
string(3) "ONE"
[2]=>
string(3) "TWO"
[3]=>
&string(5) "THREE"
}

If you follow Stefan Gehrig's comments on question, there is a link that perfectly explains this behaviour: http://schlueters.de/blog/archives/141-References-and-foreach.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.