Solved

Array question

Posted on 2007-04-09
15
197 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 143

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
Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

 
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Author Note: Since this E-E article was originally written, years ago, formal testing has come into common use in the world of PHP.  PHPUnit (http://en.wikipedia.org/wiki/PHPUnit) and similar technologies have enjoyed wide adoption, making it possib…
Developers of all skill levels should learn to use current best practices when developing websites. However many developers, new and old, fall into the trap of using deprecated features because this is what so many tutorials and books tell them to u…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
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 …

828 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