Reputation: 5936
I have trying to modify values using pointers within nested foreach loops in PHP.. The following line however does not seem work:
// Assign a the attribs value to the array
$link_row['value'] = $args[ $u_value ];
The variable $args[ $u_value ]; is populated and can be output without issue, but when i added it to the $link_row reference it just doesnt seem to set..
foreach ($unique_links as $link_id => &$link_attr)
{
foreach($link_attr as &$link_row)
{
foreach($link_row as $u_attr => &$u_value)
{
if ($u_attr == 'attribute_name')
{
// Assign a the attribs value to the array
$link_row['value'] = $args[ $u_value ];
// If one of the values for the unique key is blank,
// we can remove the entire
// set from being checked
if ( !isset($args[ $u_value ]) )
{
unset($unique_links[$link_id] );
}
}
}
}
}
Upvotes: 3
Views: 3607
Reputation: 6956
You must always unset variables after using them in a foreach
. Even if you have two foreach(..)
statements one right after the other. Even if you have a foreach(..)
inside another foreach(..)
. No exceptions!
foreach ($unique_links as $link_id => &$link_attr)
{
foreach($link_attr as &$link_row)
{
foreach($link_row as $u_attr => &$u_value)
{
if ($u_attr == 'attribute_name')
{
// Assign a the attribs value to the array
$link_row['value'] = $args[ $u_value ];
// If one of the values for the unique key is blank,
// we can remove the entire
// set from being checked
if ( !isset($args[ $u_value ]) )
{
unset($unique_links[$link_id] );
}
}
}
unset($u_value); // <- this is important
}
unset($link_row); // <- so is this
}
unset($lnk_attr); // <- and so is this, even if you reached the end of your program or the end of a function or a method and even if your foreach is so deeply indented or on such a long line that you're not sure what code might follow it, because another developer (maybe even you) will come back and read the code and he might not see that you used a reference in a foreach
Here's another fun piece of code that messed up a big project not long ago:
foreach ($data as $id => &$line) {
echo "This is line {$id}: '{$line}'\n";
$line .= "\n";
}
echo "And here is the output, one line of data per line of screen:\n";
foreach ($data as $id => &$line) {
echo $line;
}
The fact that someone didn't unset($line)
right after the first foreach(..)
really messed up the data in the array, because &$line
was a reference and the second foreach(..)
assigned it a different value as it looped through the data and it kept overwriting the last line of data.
Upvotes: 6
Reputation: 16768
Since I can't see your arrays I don't know which are integer, which associate, etc.
As far I can see there is no reason for the refernece of $u_value. It doesn't do any harm, but makes no difference either way.
More importantly, any time your second if condition would be true you will have an error before you reach it on the line
$link_row['value'] = $args[ $u_value ];
maybe you'd like to use
$link_row['value'] = isset($args[$u_value]) ? $args[ $u_value ] : "NOT PRESENT";
The line you mention seems to work just fine.
My code:
$args = array(100,200,300,400,500);
$unique_links = array (array( 'a' => array('attribute_name' => 1,'x' => 2, 'y' => 3, 'z' =>4),
'b' => array('attribute_name' => 3,'x' => 2, 'y' => 3, 'z' =>4),
'c' => array('attribute_name' => 0,'x' => 2, 'y' => 3, 'z' =>4),
'd' => array('attribute_name' => 7,'x' => 2, 'y' => 3, 'z' =>4),
'e' => array('attribute_name' => 1,'x' => 2, 'y' => 3, 'z' =>4)
));
echo_r($unique_links);
foreach ($unique_links as $link_id => &$link_attr)
{
foreach($link_attr as &$link_row)
{
foreach($link_row as $u_attr => $u_value)
{
echo "     $u_attr is $u_value <br />";
if ($u_attr == 'attribute_name')
{
// Assign a the attribs value to the array
$link_row['value'] = isset($args[$u_value]) ? $args[ $u_value ] : "NOT PRESENT";
// If one of the values for the unique key is blank, we can remove the entire
// set from being checked
if ( !isset($args[ $u_value ]) )
{
//echo "want to kill: $link_id <br />";
//unset($unique_links[$link_id] );
}
}
}
echo "<br />";
}
}
echo_r($unique_links);
My output:
Array
(
[0] => Array
(
[a] => Array
(
[attribute_name] => 1
[x] => 2
[y] => 3
[z] => 4
)
[b] => Array
(
[attribute_name] => 3
[x] => 2
[y] => 3
[z] => 4
)
[c] => Array
(
[attribute_name] => 0
[x] => 2
[y] => 3
[z] => 4
)
[d] => Array
(
[attribute_name] => 7
[x] => 2
[y] => 3
[z] => 4
)
[e] => Array
(
[attribute_name] => 1
[x] => 2
[y] => 3
[z] => 4
)
)
)
attribute_name is 1
x is 2
y is 3
z is 4
value is 200
attribute_name is 3
x is 2
y is 3
z is 4
value is 400
attribute_name is 0
x is 2
y is 3
z is 4
value is 100
attribute_name is 7
x is 2
y is 3
z is 4
value is NOT PRESENT
attribute_name is 1
x is 2
y is 3
z is 4
value is 200
Array
(
[0] => Array
(
[a] => Array
(
[attribute_name] => 1
[x] => 2
[y] => 3
[z] => 4
[value] => 200
)
[b] => Array
(
[attribute_name] => 3
[x] => 2
[y] => 3
[z] => 4
[value] => 400
)
[c] => Array
(
[attribute_name] => 0
[x] => 2
[y] => 3
[z] => 4
[value] => 100
)
[d] => Array
(
[attribute_name] => 7
[x] => 2
[y] => 3
[z] => 4
[value] => NOT PRESENT
)
[e] => Array
(
[attribute_name] => 1
[x] => 2
[y] => 3
[z] => 4
[value] => 200
)
)
)
I comment out the unnset because it seems to kill the whole array, not just the part you intend. I guess its some weird behavior due to killing the part you are currently iterating.
Upvotes: 0
Reputation: 85318
I think you might be overwriting the value in the loop. To test this you could do something like this
$link_row['value'] = $args[ $u_value ];
Change this to
$link_row[] = $args[ $u_value ];
Then outside of the loops add this
echo "Link Row Value(s):<pre>".print_r($link_row,true)."</pre><br />\n";
This will show all of the values that are being cast/set to $link_row['value'], if you see more than one index the values are being overwritten
Upvotes: 0