Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why cant i push element onto sub array in foreach loop?

I'm trying to understand something about arrays in for each loops that might be obvious to many.

When i loop through my multi-dimensional array, i attempt to find sub arrays with no third element. If they have no third element, i want to add a third element to that sub array with a specific value.

$testArray = array (
    array("Green", "Yellow", "Blue"),
    array("Brown", "Silver"),
    array("Orange", "Pink", "Black"),
);

When i use the foreach loop:

foreach ( $testArray as $key => $array ) {
    if (count($array) == '2') {
        $array[] = "None";
    };
}

No errors are thrown but nothing happens. When i use the for each loop:

foreach ( $testArray as $key => $array ) {
    if (count($array) == '2') {
        $testArray[$key][] = "None";
    };
}

It works as expected.

Sorry for the long preamble, my questions is:

Why aren't these two foreach loops doing the same thing? Thanks!

like image 418
jreidko Avatar asked Jan 27 '26 15:01

jreidko


2 Answers

Because you need to access $testArray entries "by reference"

foreach ( $testArray as &$array ) {
    if (count($array) == 2) {
        $array[] = "None";
    };
}
unset($array);
like image 56
Mark Baker Avatar answered Jan 30 '26 04:01

Mark Baker


The problem here lies in the fact that foreach iterates over iterables and sets the iteration variable by value. This means that the $array which you are dealing with in the foreach is not the same value of the $testArray.

To rememdy this (and avoid introducing an $index variable to mutate an item in the array), you will need to tell foreach to pass the value by reference. References are PHP's answer to C-style pointers. If a variable references another, both variables point to the same value, so a modification to the contents of one is in effect a modification to the other. In your foreach, you can use &$array to have the loop pass you the items of $testArray by reference instead of by value:

foreach ( $testArray as $key => &$array ) {
    if (count($array) == '2') {
        $array[] = "None";
    }
}

(Codepad Demo)

This aligns with PHP's references, where one variable can be made to reference another like so:

$a = array(1, 2, 3);
$b = &$a;
$b[] = 4;

print_r($a); // 1, 2, 3, 4

(Codepad Demo)

You experience a similar phenomenon with functions:

function byValue($a) {
    $a[] = 4;
}

function byRef(&$a) {
    $a[] = 5;
}

$a = array(1, 2, 3);

byValue($a);
print_r($a); // 1, 2, 3

byRef($a);
print_r($a); // 1, 2, 3, 5

(Codepad Demo)

The references section of the PHP docs has some examples about this syntax of foreach. Also note this (somewhat) related, but interesting read on foreach and references.


Also, on an unrelated note if you weren't aware: you don't need a semicolon after closing a block with } in PHP unless you're doing something like assigning a closure to a variable:

$someFunc = function($a) { return $a; }; //need one here

if(1 + 2 == 4) {
   echo "I just broke math";
} // but you don't need one here
like image 35
Bailey Parker Avatar answered Jan 30 '26 04:01

Bailey Parker



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!