I'm a little confused on the behavior of for loops when iterating over an array of objects.
The PHP documentation says
foreach (array_expression as $key => $value)
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
Based on that, I was under the impression $value
was a copy (by value) of the object in the array. However, to verify I just ran this test:
class test {
public $foo = 1;
function __construct($foo) {
$this->foo = $foo;
}
}
$testArray = array();
$testArray[] = new test(1);
$testArray[] = new test(2);
$testArray[] = new test(3);;
echo '$testArray' . '<pre>' . PHP_EOL;
print_r($testArray);
echo PHP_EOL . '</pre>';
foreach ($testArray as $test) {
if ($test->foo == 2) {
$temp = $test;
}
}
$temp->foo = 'copied by value or reference?';
echo '$testArray' . '<pre>' . PHP_EOL;
print_r($testArray);
echo PHP_EOL . '</pre>';
Surprisingly, the output is:
$testArray
Array
(
[0] => test Object
(
[foo] => 1
)
[1] => test Object
(
[foo] => 2
)
[2] => test Object
(
[foo] => 3
)
)
$testArray
Array
(
[0] => test Object
(
[foo] => 1
)
[1] => test Object
(
[foo] => copied by value or reference?
)
[2] => test Object
(
[foo] => 3
)
)
My confusion is that when I did the $temp = $test
assignment it did a copy by reference to the original object in the array, but I thought $test
had been copied by value according to the documentation?
OK, so maybe I just didn't pay attention to the fine print:
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
So lets try a test where we modify the object inside the loop:
class test {
public $foo = 1;
function __construct($foo) {
$this->foo = $foo;
}
}
$testArray = array();
$testArray[] = new test(1);
$testArray[] = new test(2);
$testArray[] = new test(3);;
echo '$testArray' . '<pre>' . PHP_EOL;
print_r($testArray);
echo PHP_EOL . '</pre>';
foreach ($testArray as $test) {
if ($test->foo == 2) {
$temp = $test;
$temp->foo = 'copied by value or reference?';
}
}
echo '$testArray' . '<pre>' . PHP_EOL;
print_r($testArray);
echo PHP_EOL . '</pre>';
Output:
$testArray
Array
(
[0] => test Object
(
[foo] => 1
)
[1] => test Object
(
[foo] => 2
)
[2] => test Object
(
[foo] => 3
)
)
$testArray
Array
(
[0] => test Object
(
[foo] => 1
)
[1] => test Object
(
[foo] => copied by value or reference?
)
[2] => test Object
(
[foo] => 3
)
)
The result is the same. It appears the object is copied by reference, even though the documentation clearly insinuates they are copied by value.
What gives?