PHP Pass By Refernce logic explanation [duplicate] - php

This question already has an answer here:
Why php iteration by reference returns a duplicate last record?
(1 answer)
Closed 8 years ago.
Can anyone explain me the output of the following PHP script:
$a = array ('zero','one','two');
foreach ($a as &$v) {
}
foreach ($a as $v) {
}
print_r($a);
Output:
Array
(
[0] => zero
[1] => one
[2] => one
)

Not really an answer, but it may help you understand what's going on.
<?php
$a = array ('zero','one','two');
foreach ($a as &$v) {
}
print_r($v); // two
$v = "four";
print_r($a);
// Array
// (
// [0] => zero
// [1] => one
// [2] => four
// )

Passing by reference, you can change value inside or outside loop.
<?php
$a = array ('zero','one','two');
foreach ($a as &$v) {
}
// before loop $v is reference to last item in array $a
// if you perform unset($v) before this loop, nothing will change in $a
foreach ($a as $v) {
// here you assigning $v values from this array in loop
}
print_r($a);
// Array
// (
// [0] => zero
// [1] => one
// [2] => one
// )

Related

Remove the whole array elements, where array element key count < 2 in PHP

Below is my code that output this array:
// update users
$where_in = array('1102','');
$admin_data = $this->db->select('id,email,domain')->where_in('id',$where_in)->get('users')->result();
echo "<pre>";print_r($admin_data);
current output array
1102,
Array
(
[0] => stdClass Object
(
[id] => 1
)
)
1111,
Array
(
[0] => stdClass Object
(
[id] => 1132
)
[1] => stdClass Object
(
[id] => 1133
)
)
I am trying to accomplish by doing this, but not getting expected result.
foreach ($admin_data as $key) {
if (count($admin_data) < 2) {
unset($admin_data);
}
}
Expected result: I want to remove whole array element, where array key less than 2. I wish to get only array with more than 1 key count like below:
1111,
Array
(
[0] => stdClass Object
(
[id] => 1132
)
[1] => stdClass Object
(
[id] => 1133
)
)
I believe you are trying to unset elements within your "$admin_data" array, however you call unset on the array itself. If you pass the index of the array element into your loop, with the element itself, then you can check if the element has less than two inner elements, and unset that element accordingly.
$elementsToRemove = [];
foreach($admin_data as $index => $key) {
if (count($key) < 2) {
$elementsToRemove[] = $index;
}
}
$newArray = array_diff_key($admin_data, array_flip($elementsToRemove));
I'm not sure if I understood, but if you have an array of arrays and want to remove the inner arrays with less than 2 elements, you could do:
<?php
$original = [
["a"],
["b", "c"],
];
$filtered = array_filter(
$original,
function ($innerArray) {
return count($innerArray) >= 2;
}
);
print_r($filtered);
The result is
Array
(
[1] => Array
(
[0] => b
[1] => c
)
)
PHP Fiddle
Check again your code, it contains some logical problems:
foreach ($admin_data as $key) {
if (count($admin_data) < 2) {
unset($admin_data);
}
}
If $admin_data has one item, the if (count($admin_data) < 2) test is true and
unset($admin_data); is executed. That means (simplifying) that the all the contents of $admin_data are deleted.
If $admin_data has two or more items, the if (count($admin_data) < 2) test is never true. And it is so for each iteration.
Both cases are not logical, because you do not need the foreach loop for this test to work. Besides, you might not want to delete $admin_data contents.
What you need to do, is to iterate through $admin_data items, check the item to see if it is an array and if that array has one item, remove the item from the $admin_data array. Or you could create another array only with the valid items.
Here is a possible example of both:
/* unset the item if it is an array with one item */
foreach ($admin_data as $key => $value) {
if (is_array($value) && count($value) === 1) {
unset($admin_data[$key]);
}
}
/* create a new array with the valid items */
$valid_admin_data = [];
foreach ($admin_data as $key => $value) {
if (is_array($value) && count($value) > 1) {
$valid_admin_data[$key] = $value;
}
}
I would also suggest you to read again the foreach documentation. Also, be consistents with names of variables, since it helps avoid misunderstandings: for instance, foreach ($admin_data as $key) could be better named to foreach ($admin_data as $value), since with one variable, you extract the value of current item.

why the last element of array changed after 2 foreach loop? [duplicate]

This question already has answers here:
Strange behavior of foreach when using reference: foreach ($a as &$v) { ... }
(2 answers)
Closed 7 years ago.
what's the magic?
the last element of $data changed, after 2 for each loop.
<?php
$data = array("1" => "a", "2" => "b");
print_r($data);
foreach($data as $k=>&$v) {}
foreach($data as $k=>$v) {}
print_r($data);
output:[2] => a after the second foreach
Array
(
[1] => a
[2] => b
)
Array
(
[1] => a
[2] => a
)
it the code change to this,the array won't change:
<?php
foreach($data as $k=>&$v) {}
foreach($data as $k=>&$v) {}
From the foreach manual:
Warning Reference of a $value and the last array element remain even
after the foreach loop. It is recommended to destroy it by unset().
So at the end of the first foreach, $v is a reference to the last element in the array. The next foreach's first iteration changes the value of $v (to the value of the first array element) which is a reference to the last element in the array, so it is changed.
$data = array("1" => "a", "2" => "b");
print_r($data);
foreach($data as $k=>&$v) {}
unset($v); // *** UNSET HERE ***
foreach($data as $k=>$v) {}
print_r($data);
Result:
Array
(
[1] => a
[2] => b
)
Array
(
[1] => a
[2] => b
)

How to skip iteration in foreach inside foreach

I have an array of values, and i want to insert the values to another array but with an if condition, if the "if" is true I want to skip the iteration.
Code:
$array=array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert=array();
foreach($array as $k1=>$v1)
{
foreach($v1 as $k2=>$v2)
{
if($v2==23)
{
break;
}
}
$insert[]=$v1;
}
final result should look like that
Array
(
[0] => Array
(
[1] => 11
[2] => 22
[3] => 44
[4] => 55
)
)
I tried using: break,return,continue...
Thanks
There are a few ways to do this. You can loop over the outer array and use array_filter on the inner array to remove where the value is 23 like this (IMO preferred; this also uses an array of $dontWant numbers so it is easier to add or change numbers later):
<?php
$array = array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert = array();
//array of numbers you don't want
$dontWant = array(23);
//loop over outer array
foreach($array as $subArray){
//add to $insert a filtered array
//subArray is filtered to remove where value is in $dontWant
$insert[] = array_filter($subArray, function($val) uses ($dontWant) {
//returns true if the value is not in the array of numbers we dont want
return !in_array($val, $dontWant);
});
}
//display final array
echo '<pre>'.print_r($insert,1).'</pre>';
Or you can reference the first key to add to a sub array in $insert like (which is a little more like what your code is trying to do and show that you are not too far off):
<?php
$array = array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert = array();
//loop over outer array
foreach($array as $k1=>$v1){
//add an empty array to $insert
$insert[$k1] = array();
//loop over inner array
foreach($v1 as $k2=>$v2){
//if the inner array value is not 23
if($v2 != 23){
//add to inner array in insert
$insert[$k1][] = $v2;
}
}
}
//display the result
echo '<pre>'.print_r($insert,1).'</pre>';
Both of these methods would produce the same result. IMO using array_filter is the preferred method, but the second method might be a little easier to understand for someone new to programming.
Why don't you just try it like this?
foreach($v1 as $k2=>$v2)
{
if($v2!=23)
{
$insert[]=$v2;
}
}
EDIT:
Explanation: You check with the if($v2!=23) if the value of the variable $v2 is not equal to (that is the != sign) any given number that stands after the inequality operator, and if so, it will insert that value to the array $insert.
I hope it is clear now.
Sorry, I've written $v1 instead of $v2, the code should work now.
To add variants :)
$array=array(array(1=>11,2=>22,3=>23,4=>44,5=>55));
$insert=array();
foreach($array as $a)
{
while (($i = array_search(23, $a)) !== false)
{ unset($a[$i]); sort($a); }
$insert[] = $a;
}
print_r($a);
result:
Array ( [0] => Array ( [0] => 11 [1] => 22 [2] => 44 [3] => 55 ) )

Access newly added key=>value in associative array during loop

I am trying to add a key=>value pair to an array while using a foreach loop, when that value is added the foreach loop needs to process the new key=>value pair.
$array = array(
'one' => 1,
'two' => 2,
'three' => 3
);
foreach($array as $key => $value) {
if ($key == 'three') {
$array['four'] = 4;
} else if ($key == 'four') {
$array['five'] = 5;
}
}
If I print the array after the loop, I would expect to see all 5 kv's, but instead I only see this:
Array
(
[one] => 1
[two] => 2
[three] => 3
[four] => 4
)
Is there some way, when I add the fourth pair, to actually process it so the fifth pair gets added within that foreach loop (or another kind of loop?)
According to php documentation,
As foreach relies on the internal array pointer changing it within the loop may lead to unexpected behavior.
You cannot modify the array during foreach. However, an user posted an example of a regular while loop that does what you need: http://www.php.net/manual/en/control-structures.foreach.php#99909
I report it here
<?php
$values = array(1 => 'a', 2 => 'b', 3 => 'c');
while (list($key, $value) = each($values)) {
echo "$key => $value \r\n";
if ($key == 3) {
$values[4] = 'd';
}
if ($key == 4) {
$values[5] = 'e';
}
}
?>
the code above will output:
1 => a
2 => b
3 => c
4 => d
5 => e
That's because PHP will internally use it's own copy of the array pointer. You are iterating trough it's orginal key/values not through the modified array.
As the original array contains the key three, the first if statement will match, but not the second
Another simpler example is the fact, that this is not an infinite loop:
$array = array(1);
foreach($array as $val) {
$array []= $val +1;
}
var_dump($array);
Output:
array(2) {
[0] =>
int(1)
[1] =>
int(2)
}
However, the PHP documentation says not much to that:
As foreach relies on the internal array pointer changing it within the loop may lead to unexpected behavior.

Trying to loop through array and reassign value

I have two arrays, both with the same indexes. What I want to do is loop through one of the arrays (portConfigArray), and change the value of an existing item by using data from a second array. (portStatusArray)
Here's the logic:
$i=0;
foreach ($portConfigArray as $configentry)
{
$configentry['LinkState'] = $portStatusArray[$i]['LinkState'];
$i = $i + 1;
echo $configentry['LinkState'];
}
$portdetailsArray = $portConfigArray;
var_dump($portdetailsArray);
the echo statement shows the correct values being assigned for each item in the portConfigArray. (its just a string value like "Up" or "Down")
But in the var_dump I can see that the value hasn't been updated correctly. It shows
["LinkState"]=> string(0) ""
as the output for each record.
Can you tell me what I'm doing wrong?
You need to make $configentry a reference, otherwise it's just a copy
foreach ($portConfigArray as &$configentry)
foreach ($portConfigArray as $configentry)
Should be
foreach ($portConfigArray as &$configentry)
Essentially this means the loop deals with the actual value rather than a copy of it.
While you can make $configentry a reference, as stated in other answers, it CAN cause major issues if you reuse such "referenced" variables later on in the script for other purposes. A safer method is to use the key=>val version of foreach, and directly modify the array:
foreach($portConfigArray as $key => $configentry) {
$portConfigArray[$key] = 'newvalue';
}
The reference version can cause issues, e.g.
php > $a = array('a', 'b', 'c');
php > foreach($a as &$val) { $val++; };
php > print_r($a);
Array
(
[0] => b
[1] => c
[2] => d
)
php > $b = array('p', 'q', 'r');
php > foreach($b as $val) { $val++; }; <--note, $val, not &$val
php > print_r($b);
Array
(
[0] => p <---hey, these 3 didn't change!
[1] => q
[2] => r
)
php > print_r($a);
Array
(
[0] => b
[1] => c
[2] => s <---uh-oh!
)
php >

Categories