Solved

Array question

Posted on 2007-04-09
15
186 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
 
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
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

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…
Foreword (July, 2015) Since I first wrote this article, years ago, a great many more people have begun using the internet.  They are coming online from every part of the globe, learning, reading, shopping and spending money at an ever-increasing ra…
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

762 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

17 Experts available now in Live!

Get 1:1 Help Now