What happened to this note:"Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it."

Lots of people think the answer is two() because it uses "reference to value, which it doesn't have to copy each value when it loops".

Well, that's totally wrong!

Here's what actually happens:

* one():

- This function takes an array as argument ($arr).- The array function argument itself isn't passed by reference, so the function knows it isn't allowed to modify the original at all.- Then the foreach loop happens. The array itself wasn't passed by reference to the function, so PHP knows that it isn't allowed to modify the outside array, so it therefore makes a copy of the array's internal iteration offset state (that's just a simple number which says which item you are currently at during things like foreach()), which costs almost no performance or memory at all since it's just a small number.- Next, it uses that copied iteration offset to loop through all key/value pairs of the array (ie 0th key, 1st key, 2nd key, etc...). And the value at the current offset (a PHP "zval") is assigned to a variable called $val.- Does $val make a COPY of the value? That's what MANY people think. But the answer is NO. It DOESN'T. It re-uses the existing value in memory. With zero performance cost. It's called "copy-on-write" and means that PHP doesn't make any copies unless you try to MODIFY the value.- If you try to MODIFY $val, THEN it will allocate a NEW zval in memory and store $val there instead (but it still won't modify the original array, so you can rest assured).

Alright, so what's the second version doing? The beloved "iterate values by reference"?

* two():

- This function takes an array as argument ($arr).- The array function argument itself isn't passed by reference, so the function knows it isn't allowed to modify the original at all.- Then the foreach loop happens. The array itself wasn't passed by reference to the function, so PHP knows that it isn't allowed to modify the outside array.- But it also sees that you want to look at all VALUES by reference (&$val), so PHP says "Uh oh, this is dangerous. If we just give them references to the original array's values, and they assign some new value to their reference, they would destroy the original array which they aren't allowed to touch!".- So PHP makes a FULL COPY of the ENTIRE array and ALL VALUES before it starts iterating. YIKES!

Therefore: STOP using the old, mythological "&$val" iteration method! It's almost always BAD! With worse performance, and risks of bugs and quirks as is demonstrated in the manual.

You can always manually write array assignments explicitly, without references, like this:

The main lesson is this: DON'T blindly iterate through values by reference! Telling PHP that you want direct references will force PHP to need to copy the WHOLE array to protect its original values! So instead, just loop normally and trust the fact that PHP *is* actually smart enough to never copy your original array's values! PHP uses "copy-on-write", which means that attempting to assign something new to $val is the ONLY thing that causes a copying, and only of that SINGLE element! :-) But you never do that anyway, when iterating without reference. If you ever want to modify something, you use the "$a[$key] = 123;" method of updating the value.

I want to add some inline comments to dtowell's piece of code about the iteration by reference:

<?php

$a = array('abe','ben','cam');

foreach ($a as $k=>&$n)$n = strtoupper($n);

# At the end of this cycle the variable $n refers to the same memory as $a[2]# So when the second "foreach" assigns a value to $n :

foreach ($a as $k=>$n) // notice NO reference here!echo "$n\n";

# it is also modifying $a[2] .# So on the three repetitions of the second "foreach" the array will look like:# 1. ('abe','ben','abe') - assigned the value of the first element to the last element# 2. ('abe','ben','ben') - assigned the value of the second element to the last element# 3. ('abe','ben','ben') - assigned the value of the third element to itself

modifying array while foreach'ing it(yeah, such slime code;-)if elements were added on last iteration or into array with 1 element, then added elements wont be iterated as foreach checks for pointer before iteration cycleso it just quit and added elements wont be treated

String keys of associative arrays, for which is_numeric() is true and which can be type-juggled to an int will be cast to an int! If the key is on the other hand a string that can be type-juggled into a float, it will stay a string. (Observed on PHP 7.0.0RC8)

foreach by reference internally deleted and created a new reference in each iteration, so it is not possible to directly use this value as a variable parameter values​​, look at the following example where the problem is observed and a possible solution:

<?php$d3 = array('a'=>array('b'=>'c'));foreach($d3['a'] as &$v4){}foreach($d3 as $v4){}var_dump($d3);?>will get something look like this:array(1) { ["a"]=> array(1) { ["b"]=> &array(1) { ["b"]=> *RECURSION* } }}then you try to walk some data with this array.the script run out of memory and connect reset by peer

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

If you accidentally put a semicolon after the foreach statement, you get no errors, but the loop will only run on the last element of the array:<?php$array = array(1,2,3);foreach ($array as $key);{ echo $key;}// output: 3?>

This is a decent, simple, and easy way to reference other values of an associative array when using foreach. (effective "next", "prev", etc.)The only care that needs to be taken is if the array is HUGE in size, so you don't run into memory use problems. (and potential speed issues)

This example uses the 'primary' array, $aPublishSeq, which is ksort-ed to put the array in order according to the associative keys. The array is then copied using a foreach loop to make a duplicate array where the key and value order correspond to the first array, but the keys are sequential numeric starting at zero.

You can even iterate through "dynamic" arrays that do not physically exist, but are objects that implement Iterator interface. They don't need to be stored in memory when foreach starts.

Consider the array that contains some values (I called it $allValues in the example below) and we want to have only some of them (eg. the ones that are dividable by 2). I create an object that would serve as dynamic array, that means it would "dynamically update" its values together with $allValues. The main advantage is that I store only one array, and it's the only array I serialize.

An object of MyIter class will not contain any values itself:<?phpclass MyIter implements Iterator { // you can implement ArrayAccess and Countable interfaces too, this will make class MyIter behave like a "real" arrayprivate $position = 0; // an internal position of the current element // please note that $position has nothing common with $allValues!

// the all below declared methods are public and belong to the Iterator interfacefunction rewind() { // a method to start iterating$this->position = 0; // just move to the beginning}

function current() { // retrieves the current element$table=$this->getTable(); // let us prepare a tablereturn $table[$this->position]; // and return the current element}

function key() { // retrieves the current element's keyreturn $this->position; // this is used by foreach(... as $key=>$value), not important here}

function next() { // move to next element++$this->position; }

function valid() { // check if the current element is valid (ie. if it exists)return array_key_exists($this->position, $this->getTable()); }} // end of class

// now prepare the array of 12 elements$allValues=array(0,1,2,3,4,5,6,7,8,9,10,11);

//we would like to have a dynamic array of all even values$iterator=new MyIter();

foreach($iterator as $value){ echo $value."<br />";}?>This will result in:0246810

(You may also like to see what var_dump($iterator) produces).

Another great advantage is that you can modify the main table "on-the-fly" and it has its impact. Let us modify the last foreach loop:<?php// ...all above shall stay as it wasforeach($iterator as $value){ echo $value."<br />"; if($value==6){$allValues=array(2,3); echo "I modified source array!<br />"; }}?>This produces now:0246I modified source array!

However, if you feel it is rather a catastrophic disadvantage (maybe for example, it shows the values 0, 4, and 6 which were removed when we reached 6), and wish to have a "static" array that will iterate even in modified objects, just call getTable() in rewind() method and save it in temporary (private perhaps) field. In my example getTable() is called every iteration, and it calls another foreach through $allValues, which together might be time-consuming. Consider what you need.