?
Solved

Array question

Posted on 2007-04-09
15
Medium Priority
?
214 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
  • 3
  • +1
15 Comments
 
LVL 143

Assisted Solution

by:Guy Hengel [angelIII / a3]
Guy Hengel [angelIII / a3] earned 400 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 400 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
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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 51

Accepted Solution

by:
Steve Bink earned 1200 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 51

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 51

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 51

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 51

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

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…
There are times when I have encountered the need to decompress a response from a PHP request. This is how it's done, but you must have control of the request and you can set the Accept-Encoding header.
The viewer will learn how to count occurrences of each item in an array.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…
Suggested Courses

718 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