Copying an array on assignment
As you already know, $b = $a copies a number or a string: a later change to $a does not touch $b. But what if $a holds a whole array—a cloakroom with all its hooks and items?
Picture asking the attendant: "Make me another one exactly like this." And a second cloakroom appears next to the first—with the same hooks and the same items on them. Now there are two cloakrooms: hang a coat in the second one, and nothing changes in the first.
In PHP, assigning an array works exactly like that: $b = $a gives you a second, independent array. Click "Next step" and watch $a and $b in the {main} frame: after the assignment, each write changes only one of them.
1<?php2 3$a = [1, 2];4$b = $a;5$b[] = 3;6$a[0] = 9;7echo count($a), ' ', count($b), "\n";8echo $a[0], ' ', $b[0], "\n";
$a holds an array of two elements.
Let's sum up what the example showed:
$b = $acreates a second array with the same elements,[1, 2].$b[] = 3adds an element to$bonly:count($a)stays2, whilecount($b)becomes3.$a[0] = 9changes only$a, so$b[0]is still1.- The program prints
2 3and9 1.
Interviewers like to ask this, especially of people who know Python or JavaScript. There, b = a gives a second name to the same list, and a change through b is visible through a. In PHP an array is copied on assignment, and the variables live apart.
Nested arrays are copied too
The whole cloakroom is copied together with the bags on its hooks: in the copy, the nested arrays become separate too.
<?php
$menu = ['drinks' => ['tea', 'coffee']];
$copy = $menu;
$copy['drinks'][] = 'juice';
echo count($menu['drinks']), ' ', count($copy['drinks']), "\n"; // 2 3
echo implode(' ', $menu['drinks']), "\n"; // tea coffeeThe line $copy['drinks'][] = 'juice' changes only the list inside $copy. $menu still has two drinks, tea and coffee.
When PHP makes the copy
Copying a large array on every $b = $a would be slow, so PHP puts this work off. Right after the assignment, both variables look at the same data, and the real copy appears on the first write to one of them. This technique is called copy-on-write.
For your program it makes no difference: the arrays behave as two independent ones. This is where the cloakroom picture stops working: a real second cloakroom is built at once, while PHP builds it only when someone hangs up or takes down an item.
An array in a function
The same happens when an array is passed to a function: the parameter gets its own copy of the array. If the function adds an element to the parameter, the array passed in the call stays as it was.
Thanks to copy-on-write, passing a large array to a function is cheap. Interviewers ask how much it costs to pass an array of a million elements to a function. The answer: almost nothing while the function only reads it—PHP copies the data only once the function starts writing to it.
Common mistake
Everyone's age is increased in a foreach loop by changing the loop variable:
$users = [
['name' => 'Anna', 'age' => 31],
['name' => 'Boris', 'age' => 25],
];
foreach ($users as $user) {
$user['age'] = $user['age'] + 1; // ✗
}
echo $users[0]['age'], ' ', $users[1]['age'], "\n"; // 31 25The program runs without a message, but the ages do not change: it prints 31 25. You saw this in the loops theme: foreach puts a copy of the element into $user, and the element here is a whole card. The write changes the copy, and the copy is gone after the iteration.
Write into the array itself by key: foreach ($users as $i => $user) { $users[$i]['age'] = $user['age'] + 1; }. After such a loop it prints 32 26.
Key points
$b = $agives a second, independent array: a write to one is not visible in the other.- Nested arrays are copied together with the outer one, and a parameter of a function gets a copy too.
- PHP copies the data only on the first write—this is copy-on-write, and for the program the arrays are independent all the same.
- The
foreachloop variable is a copy of the element, so the array is changed by key:$users[$i]['age'] = ….