24

What is the difference between

foreach ($my_array as $my_value) {
}

And:

foreach ($my_array as &$my_value) {
}

?

May I ask you to give me two real-world examples of when to use one and when you use the other?

Olivier Pons
  • 15,363
  • 26
  • 117
  • 213
  • 3
    As a rule of thumb, never use references. – troelskn Dec 29 '10 at 15:21
  • 6
    @troelskn: That is a stupid rule of thumb. Sometimes you have to use them. If you don't know whether you should use them, then you probably don't have to. But whenever you want to modify the actual value you have to use references. – Felix Kling Dec 29 '10 at 15:25
  • 1
    @Felix Kling: I do agree with @troelskn. I've never had the need to modify the actual value of an array. Each time I had to, you can do much nicer code than using ('&$var'). The only way I can think of may be... optimization: if you use '&', I suppose (correct me if I'm wrong) that there's no need to make a copy into a temporary variable. Thus gain of execution time. If you have an example where you can't avoid loops like the one with the '&' in my question, may I ask you to show them as a comment here? Thank you very much! – Olivier Pons Dec 29 '10 at 16:30
  • @oliver Actually, in most cases using a reference is *slower*, due to PHP's internal mechanics. – troelskn Dec 29 '10 at 16:34
  • 3
    @felix My point is that if you need references to do what you want, then you're doing something wrong. Refactor your code instead. – troelskn Dec 29 '10 at 16:36
  • @Olivier Pons, @troelskn: Ok, I don't know if you only referring to `foreach` or references in general, but e.g. if you have a recursive function that should process an array, then most often it is easier to define the function like `fun(&$array)` instead of handling return parameters. But anyway, references are not *bad* in general. You wouldn't say someone is doing something wrong if he is using pointers in C, would you? – Felix Kling Dec 29 '10 at 17:12
  • @troelskn: Of course there are appropriate times to use references. You do realize that objects references (identifiers) are passed to functions don't you? Or are you cloning them before each pass? ;) @Olivier Pons: PHP employs copy-on-write so if you're not modifying the variables then passing by reference saves no time. – webbiedave Dec 29 '10 at 18:16

5 Answers5

31

The first example creates a copy of the value, whereas the second uses a reference to the original value. So after the first foreach runs, the original array is still untouched. After the second foreach the original array could have been modified since it was handled by reference.

Some native PHP functions already work this way, such as shuffle() which rearranges the contents of your array. You'll notice that this function doesn't return an array, you just call it:

$myArray = array('foo', 'bar', 'fizz', 'buzz');
shuffle( $myArray );
// $myArray is now shuffled

And it works its magic since it works with the array by reference rather than creating a copy of it.

Then there are functions that don't pass anything by reference but rather deal with a copy of the original value, such as ucwords() which returns the new resulting string:

$myString = "hello world";
$myString = ucwords( $myString );
// $myString is now capitalized

See Passing by Reference.

Sampson
  • 265,109
  • 74
  • 539
  • 565
  • 2
    if $my_value is an object, it inevitably passed by reference. – Epharion Dec 29 '10 at 15:21
  • 1
    @Epharion: No, PHP always passes by val unless it is told to pass by ref. And objects are no exception to this. Only with objects a pass by val performs very similar to a pass by ref due to the way PHP stores objects ;) – NikiC Dec 29 '10 at 16:33
8

Jonathan's answers describes it very well. Just for completeness, here are your two examples:

  1. Just reading values:

    $my_array = range(0,3);
    foreach ($my_array as $my_value) {
        echo $my_value . PHP_EOL;
    }
    
  2. Adding some number to each element (thus modifying each value):

    foreach ($my_array as &$my_value) {
        $my_value += 42;
    }
    

    If you don't use &$my_value, then the addition won't have any effect on $my_array. But you could write the same not using references:

    foreach($my_array as $key=>$value) {
        $my_array[$key] = $value + 42;
    }
    

    The difference is that we are accessing/changing the original value directly with $my_array[$key].

DEMO

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
0

When you prefix a variable with an ampersand, you’re creating a “reference.” PHP references are like shortcuts or symlinks on your computer. You can create a pointer variable that is just another name for the same data.

I dont see a big difference in using these, except that you DONT COPY a variable saving memory. When you are passing variables you can just pass the reference and the reference points to the original object.

tHeSiD
  • 4,587
  • 4
  • 29
  • 49
  • A typical beginner mistake: To think that PHP is stupid. PHP doesn't blindly copy values. It uses the copy-on-write concept, i.e. that the value only is copied, when it is changed. Creating references for performance reasons normally is only contraproductive, because it often causes PHP to make only more copying. – NikiC Dec 29 '10 at 16:38
0

A real world example for & use is when you need to change the content of an array with very few lines of code

foreach($arrFeed as &$objFeed)
  $objFeed['externalSrc'] = convertToLocalImage($objFeed['externalSrc']);
johnlemon
  • 20,761
  • 42
  • 119
  • 178
0

I only use references when i have to read csv files to know what is the delimitier. Just take the first line:

$handle = fopen($file, "r");
$firstLine = fgets($handle);
fclose($handle);

Then with this possible delimitiers

$delimiters = array(';' => 0,',' => 0,"\t" => 0,"|" => 0);

Count by reference what is the most used

foreach ($delimiters as $delimiter => &$count) {
    $count = count(str_getcsv($firstLine, $delimiter));
}
$delimiter =  array_search(max($delimiters), $delimiters);
Wilbax
  • 1