Skip to content

Instantly share code, notes, and snippets.

@JohnRoux
Last active November 11, 2016 08:52
Show Gist options
  • Save JohnRoux/4d21b9b364c1d8f46168aee85f12c923 to your computer and use it in GitHub Desktop.
Save JohnRoux/4d21b9b364c1d8f46168aee85f12c923 to your computer and use it in GitHub Desktop.
Demo of how using references in PHP loops can be extremely beneficial, but beware of potential issues!
Welcome to the Demo
This is going to look at the differences of iterating through loops, passing via reference and passing via value in PHP. Basically this is all a matter of PHP scope, at what point do objects exist and are you actually editing what you think you are?
Original Array
/var/www/dev.runwaysale.local/runwaysale/refdemo.php:20:
array (size=4)
'Name' => string 'Fred' (length=4)
'Description' => string 'Man' (length=3)
'Gender' => string 'Male' (length=4)
'Country' => string 'South Africa' (length=12)
Example 1 : After Swapping M's with S's without using reference passing
You might notice that nothing has actually changed, because when you use a foreach($arrayFoo as $row), that $row doesn't point back to the actual $arrayFoo. Instead, what happens is PHP reads a row in $arrayFoo and puts that value into $row. Thus when you change $row, it only changes for the scope of the foreach and it never actually updates it's parent array $arrayFoo. This means that no changes actually happen to the array! This can be very useful though!
/var/www/dev.runwaysale.local/runwaysale/refdemo.php:29:
array (size=4)
'Name' => string 'Fred' (length=4)
'Description' => string 'Man' (length=3)
'Gender' => string 'Male' (length=4)
'Country' => string 'South Africa' (length=12)
Example 2 : After Swapping M's with S's using reference passing
In this example, we're not creating a whole new variable and just assigning it the value of a row from $arrayFoo. No, in fact what we're doing here with the & is we are linking that $row to the actual row in $arrayFoo. This means that any changes to $row actually effect $arrayFoo!
/var/www/dev.runwaysale.local/runwaysale/refdemo.php:38:
array (size=4)
'Name' => string 'Fred' (length=4)
'Description' => string 'San' (length=3)
'Gender' => string 'Sale' (length=4)
'Country' => string 'South Africa' (length=12)
So that's all pretty cool, if we want to change the actual array whilst iterating over it's rows, we use pass by reference. But why is PHP a bit wierd here?
Well, you see, after you're foreach has completed. $row still actually exists. This is the case for reference and value passing btw. It's a PHP thing.
After the foreach in Example 1. We can still call $row and it is set! It is going to be the last value it was before the foreach ended. Thus it will be 'South Africa'. The same thing with Example 2!
The difference here though, between Example 1 and Example 2 is that if you were to change $row after Example 1, it won't do anything because it's not linked to the actual array. Whereas if you change $row after the loop in Example 2, it will actually alter your array. So I'm going to do it. We're long past the foreach in example 2, but I'm going to change $row and dump the array
So, if you're not sure what happens after your foreach, a safety net would be to unset $row so that if anyone does edit it after the case, it won't effect your array - Simply use unset($row);. Then again, if your array is being returned or pushed into a different scope and you know $row isn't going to follow, there's no need to unset $row.
<?php
/**
* Created by PhpStorm.
* User: vulcan
* Date: 2016/11/11
* Time: 10:09 AM
*/
//Setting up Conditions
echo "<h1>Welcome to the Demo</h1><p>This is going to look at the differences of iterating through loops, passing via reference and passing via value in PHP. Basically this is all a matter of PHP scope, at what point do objects exist and are you actually editing what you think you are?</p><hr>";
$arrayFoo = array(
"Name" => "Fred",
"Description" => "Man",
"Gender" => "Male",
"Country" => "South Africa"
);
//Starting off
echo "<h2>Original Array</h2>";
var_dump($arrayFoo);
//Changing $row, but only in the scope of the foreach, so $row is actually a duplicate, not a reference
foreach($arrayFoo AS $row){
$row = str_replace("M", "S", $row);
}
echo "<br><h2>Example 1 : After Swapping M's with S's without using reference passing</h2>";
echo "<p>You might notice that nothing has actually changed, because when you use a foreach(\$arrayFoo as \$row), that \$row doesn't point back to the actual \$arrayFoo. Instead, what happens is PHP reads a row in \$arrayFoo and puts that <em>value</em> into \$row. Thus when you change \$row, it only changes for the scope of the foreach and it never actually updates it's parent array \$arrayFoo. This means that no changes actually happen to the array! This can be very useful though!";
var_dump($arrayFoo);
//Changing ArrayFoo, with references to the actual $arrayFoo and not a duplicate
foreach($arrayFoo AS &$row){
$row = str_replace("M", "S", $row);
}
echo "<br><h2>Example 2 : After Swapping M's with S's using reference passing</h2>";
echo "<p>In this example, we're not creating a whole new variable and just assigning it the value of a row from \$arrayFoo. No, in fact what we're doing here with the <i>&</i> is we are linking that \$row to the actual row in \$arrayFoo. This means that any changes to \$row actually effect \$arrayFoo!";
var_dump($arrayFoo);
echo "<hr><br><p>So that's all pretty cool, if we want to change the actual array whilst iterating over it's rows, we use pass by reference. But why is PHP a bit wierd here?";
echo "<p>Well, you see, after you're foreach has completed. \$row still actually exists. This is the case for reference and value passing btw. It's a PHP thing.";
echo "<p>After the foreach in Example 1. We can still call \$row and it is set! It is going to be the last value it was before the foreach ended. Thus it will be 'South Africa'. The same thing with Example 2!";
echo "<p>The difference here though, between Example 1 and Example 2 is that if you were to change \$row after Example 1, it won't do anything because it's not linked to the actual array. Whereas if you change \$row after the loop in Example 2, it will actually alter your array. So I'm going to do it. We're long past the foreach in example 2, but I'm going to change \$row and dump the array";
$row = "Well this is awkward";
var_dump($arrayFoo);
echo "<br><hr><p>So, if you're not sure what happens after your foreach, a safety net would be to unset \$row so that if anyone does edit it after the case, it won't effect your array - Simply use <i>unset(\$row);</i>. Then again, if your array is being returned or pushed into a different scope and you know \$row isn't going to follow, there's no need to unset \$row.";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment