Solved

Array question

Posted on 2007-04-09
15
192 Views
Last Modified: 2007-04-09
Hi,
I am reading the php manual on php.net
I can see a sample code like this :




<?php
$colors = array('red', 'blue', 'green', 'yellow');
// PHP 5
foreach ($colors as &$color) {
    $color = strtoupper($color);
}
unset($color); /* ensure that following writes to
$color will not modify the last array element */

// Workaround for older versions
foreach ($colors as $key => $color) {
    $colors[$key] = strtoupper($color);
}

print_r($colors);
?>

The above example will output:

Array
(
    [0] => RED
    [1] => BLUE
    [2] => GREEN
    [3] => YELLOW
)



But I do not understand why the unset is needed,
indeed if I remove unset, I have this :

Array
(
    [0] => RED
    [1] => BLUE
    [2] => GREEN
    [3] => GREEN
)

and the last value YELLOW disappeaered.

Can someone help me understand why ?
(
the link to the manual , array part :
http://www.php.net/manual/en/language.types.array.php
)

0
Comment
Question by:matthew016
  • 6
  • 5
  • 3
  • +1
15 Comments
 
LVL 142

Assisted Solution

by:Guy Hengel [angelIII / a3]
Guy Hengel [angelIII / a3] earned 100 total points
ID: 18878285
the unset is needed because of the & in the following line:
>foreach ($colors as &$color) {

which make &$color a reference variable, and not only a variable having the value.
that way, the line:
$color = strtoupper($color);
will indeed change the array item.
if you remove the & in the above line, the array items will NOT get changed, and the output would be:

Array
(
    [0] => red
    [1] => blue
    [2] => green
    [3] => yellow
)
0
 
LVL 15

Assisted Solution

by:Tomeeboy
Tomeeboy earned 100 total points
ID: 18878311
The ampersand in front of the variable $color is making it a reference to the array value, which means that any changes to $color will effect the array value, and vice versa.  Since it loops through the array, the last reference set is to the last value of the array, which means if that value, or $color is modified afterwards, they both get changed.

Hope that helps a bit :)
0
 
LVL 9

Author Comment

by:matthew016
ID: 18878315
i know that  &$color is a reference

But Why without unset, the last value is lost in the second loop,
this will give new values to $color :
>>foreach ($colors as $key => $color) {
0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 15

Expert Comment

by:Tomeeboy
ID: 18878325
Yeah, what he said ;)

Here's more information on that, which I dug up from a quick Google search.  It explains it fairly well and gives some examples:
http://devzone.zend.com/manual/view/page/language.variables.html
0
 
LVL 9

Author Comment

by:matthew016
ID: 18878380
I know what a reference is,
and that if u change the reference, the referenced variable is altered as well,
but does that answer to my question here ?

I still cant see why the array has its last element altered.
0
 
LVL 50

Accepted Solution

by:
Steve Bink earned 300 total points
ID: 18878411
Interesting.  Here's some code that illustrates the example more clearly:

<?
$colors = array('red', 'blue', 'green', 'yellow');
// PHP 5
foreach ($colors as &$color) {
    $color = strtoupper($color);
}
print_r($colors);
echo "<br>";
// Workaround for older versions
foreach ($colors as $key => $color) {
print_r($colors);
echo "<br>";

      echo "$key=$color<br>\n";
    $colors[$key] = strtoupper($color);
}
echo "<br>";
print_r($colors);
?>

In the first part of the example, $color is set to $colors[0] through $colors[3] in turn, but the last reference assigned is $colors[3].  Without the unset(), the second loop starts with $color pointing to the 4th element in array $colors.

Now, first iteration:  
$colors[0] = "RED"
$key = 0
$color = $colors[3] = "RED"
$colors[$key] = $colors[0] = $color (or $colors[3], which equals "RED")

Next:
$colors[1] = "BLUE"
$key = 1
$color = $colors[3] = "BLUE"
$colors[$key] = $colors[1] = $color (or $colors[3], which equals "BLUE")

Next:
$colors[2] = "GREEN"
$key = 2
$color = $colors[3] = "GREEN"
$colors[$key] = $colors[2] = $color (or $colors[3], which equals "GREEN")

Now we go the last iteration, but you can see that $colors[3] now equals "GREEN", thus 'losing' the last element of the array.

Questions?

0
 
LVL 15

Expert Comment

by:Tomeeboy
ID: 18878431
Well, some consider it a bug in PHP, but others consider it normal behaviour (including PHP.net).  You be the judge:
http://bugs.php.net/bug.php?id=29992

The 3rd post down has an explaination for the behavior.  Hope this clears things up for you somewhat ;)
0
 
LVL 9

Author Comment

by:matthew016
ID: 18878506
Thank u routinet,
yes one thing still confuses me,

Since we have this in the second loop:
>> foreach ($colors as $key => $color) {

Why is $color (which is a reference to $color[3]) not replaced by the new $color in the loop.

To make my question more clear, u have put this in your comment :
$color = $colors[3] = "BLUE"

But that means that in the second loop we have :
- $color    (  from foreach ($colors as $key => $color)  )
- $color    (  which is a reference to $color[3]  )

Two  $color  ?
0
 
LVL 50

Expert Comment

by:Steve Bink
ID: 18878552
They (the bug reporter, et al) make an interesting case.  The claim is that the foreach() construct should be responsible for clearing references used in the loop.  I refute that by saying PHP did not create the reference, so why should the engine clean it up?  

This issue is an example of why good programming practices are a must.  The last post on the report comments that this could lead to disastrous consequences if an included library does not clean up after itself.  I say that's a bug in the designer app, not in PHP, and that programmer should be cleaning up after himself or herself.

I would agree that they need to document this behavior better.  The docs don't say anything specifically regarding this.  I did see at least 5 user comments on the foreach() page for this problem, though.
0
 
LVL 50

Expert Comment

by:Steve Bink
ID: 18878586
In the second loop, $color is simply a pointer to the location of $color[3].  Any time you assign something to $color, it will be stored in, and overwrite, the space reserved for $color[3].  As I tried to illustrate in my example, $color IS being assigned the color.  In the first iteration, "RED" goes into $color, which is EXACTLY the same as "RED" going in to $colors[3].  If you stopped the loop at that point, you would see this for print_r($colors):

Array
(
    [0] => RED
    [1] => BLUE
    [2] => GREEN
    [3] => RED
)

If you stopped it after the second iteration, you would see "BLUE" in $color[3].  "GREEN" for the third iteration.  The fourth iteration is different because the loop is essentially reading a variable and storing it into the same variable.  

The loss of the 4th value happens the moment the second loop begins, unless you use unset() to remove the previous reference.  As the loop progresses, $colors[3] will store every individual value in the array, excepting the original one because it was overwritten.
0
 
LVL 9

Author Comment

by:matthew016
ID: 18878604
Thank u,

it is perfectly clear now,

well, for me that will be :

- do not use foreach ($colors as &$color) {
- use foreach ($colors as $key => $color) {
0
 
LVL 50

Expert Comment

by:Steve Bink
ID: 18878613
Using a reference in the foreach() construct is not the problem, and it can come in handy.  Don't discount it based on this issue.  Do remember to include the unset() if you use it.  

Good luck to you!
0
 
LVL 9

Author Comment

by:matthew016
ID: 18878655
I accepted the question,  I have one more question, if it doesnt bother u too much.

You explain me that using a reference in a loop can be handy,
but in this case, I don't see what u get more by using a reference,
since this :  foreach ($colors as $key => $color) {
will also change the array
0
 
LVL 50

Expert Comment

by:Steve Bink
ID: 18878723
No bother, that's why we're here.  

In this context, the reference is simply to provide for a quick shorthand back to the original.  For example, say you have an array named $my_really_long_array_name.  As you iterate through each element of the array, you want to commit a change or otherwise manipulate the original value.  If you do not use the reference:

foreach ($my_really_long_array_name as $key=>$val) {
  // do whatever up here
  // then change the original value
  $my_really_long_array_name[$key] = $newval;
}

With the reference:

foreach ($my_really_long_array_name as $key=>&$val) {
  // do whatever up here
  // then change the original value
  $val = $newval;
}
unset($val);

That's sort of basic, but you get the idea.  Imagine having a 3-, 4-, or 5- dimensional array, nested foreach() loops, and a need to change original values at multiple levels.  Those shorthand references become handy in a mighty way.
0
 
LVL 9

Author Comment

by:matthew016
ID: 18878779
Thank u  i see now    :-)
0

Featured Post

Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction HTML checkboxes provide the perfect way for a web developer to receive client input when the client's options might be none, one or many.  But the PHP code for processing the checkboxes can be confusing at first.  What if a checkbox is…
3 proven steps to speed up Magento powered sites. The article focus is on optimizing time to first byte (TTFB), full page caching and configuring server for optimal performance.
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn how to count occurrences of each item in an array.

815 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now