skip to content

In PHP, what does assignment by reference with =& do, and why can a reference taken to an array element leak changes into a copy of that array?

level: seniorimportance: should knowfreq 30%

answer

  1. two names, one content
  2. like a hard link, not a pointer
  3. unset breaks only one binding
  4. reference slots survive array copies
  5. object handles are not references

basics

~20 s

$b = &$a makes two names share one value. A reference to an array element turns that slot into a shared reference, and copying the array copies the shared slot, so writing the copy changes the original.

solid answer

~50 s

`$b = &$a;` binds both names to the **same content**; neither points to the other, and the manual likens it to a hard link. Assigning through either name changes what both see; `unset($a)` removes only the name `$a`, and `$b` keeps the value. A normal assignment such as `$c = $b;` copies the value and does **not** create a reference. The trap is arrays: after `$r = &$readings[0];`, element 0 of `$readings` is a **reference slot**. `$copy = $readings;` copies the array, but the manual notes that references inside arrays are **preserved** by normal assignment, so `$copy[0]++` also changes `$readings[0]` and `$r`. Passing that array by value to a function behaves the same. Objects are a different mechanism: variables hold **object handles**, so `$o2 = $o1` shares the object without being a reference; reassigning `$o2` does not affect `$o1`.

code

php · 12 lines
php
<?php
$a = 1;
$b = &$a;
unset($a);          // removes the name $a only
var_dump($b);       // int(1)

$o1 = new stdClass();
$o2 = $o1;          // copies the handle, not a reference
$o2->station = 'north';
var_dump($o1->station);        // string(5) "north"
$o2 = new stdClass();          // rebinds $o2 only
var_dump(isset($o1->station)); // bool(true)

go deeper

for a junior

Recall that =& makes two names share one value and that a normal assignment copies instead.

for a middle

Explain that unset breaks only one binding and that object variables hold handles, which is different from references.

for a senior

Diagnose a copied array that still changes the original by finding a live reference to one of its elements, and fix it with unset or by avoiding the reference.

for a principal

Set a codebase norm that avoids references outside tight, local cases, favouring returned values and immutable objects that tools can reason about.

## What a reference is The manual defines PHP references as **symbol table aliases**: a way to reach the same variable content through different names. They are not C pointers; there is no address and no arithmetic. The manual's analogy is Unix: variable names are directory entries, content is the file, and a reference is a **hard link**. ```php <?php $temp = 21.5; $alias = &$temp; // both names now refer to the same content $alias = 23.0; echo $temp; // 23 ``` After `$alias = &$temp;` the two names are **completely equal**: `$alias` does not point to `$temp`, both point to the same place. ## Rules of assignment by reference 1. **Normal assignment copies.** `$c = $alias;` gives `$c` its own value; later writes to `$c` affect nothing else, even though `$alias` is a reference. 2. **`unset()` breaks one binding.** `unset($temp)` removes the name `$temp`; `$alias` keeps the content. The content is destroyed only when no name refers to it. 3. **Rebinding moves one name.** `$alias = &$other;` makes `$alias` an alias of `$other`; `$temp` is unaffected. 4. **Undefined targets are created.** Taking a reference to an undefined variable, array key or property creates it with `null`. The same machinery underlies the `global` and `static` statements and passing arguments by reference; those are separate topics. ## The array-element trap The manual calls **references inside arrays** "potentially dangerous". A normal assignment with a reference on the right does not turn the left side into a reference, but references stored **inside** an array are preserved when the array is copied: ```php <?php $readings = [10, 20]; $first = &$readings[0]; // slot 0 is now a reference slot $snapshot = $readings; // a normal copy of the array... $snapshot[0] = 99; // ...but slot 0 is still shared var_dump($readings[0]); // int(99) var_dump($first); // int(99) var_dump($readings[1]); // int(20), slot 1 was copied normally ``` What happened, step by step: - `$first = &$readings[0]` turned element 0 into a reference shared by `$first` and the array slot. - Copying `$readings` copied the array, but the copy's element 0 is the **same reference**. - Writing `$snapshot[0]` therefore wrote the shared content. The manual adds that this **also applies to function calls where the array is passed by value**. A function that receives such an array and modifies element 0 changes the caller's array, even though no `&` appears in its signature. **Fix:** `unset($first);` once the reference is no longer needed. When the last other name goes away, the slot behaves like a normal value again for later copies. The same cleanup applies after a by-reference `foreach`, whose leftover reference is a well-known trap of its own. ## Objects are not references A variable holding an object holds an **object handle**. The manual notes that objects are passed around as pointers, which are not the same as references: | Code | Effect | |---|---| | `$b = $a;` (object) | both handles reach the same object; `$b->x = 1` is visible through `$a` | | `$b = new Station();` afterwards | `$b` now holds another object; `$a` is unchanged | | `$b = &$a;` then `$b = new Station();` | both names now hold the new object | So "objects are passed by reference in PHP" is a common but wrong answer: they are passed by handle, by value. ## When to use references Rarely, in modern code: - Returning a new value is clearer than modifying through an alias. - References make values harder to follow for readers and static analysers. - When you do use one, keep its scope small and `unset()` it after use.

  • How do you stop a leftover array-element reference from leaking into later copies?
    Unset the variable that holds the reference, for example `unset($first);`, as soon as you are done with it. Until then the array slot stays a shared reference, and copies of the array, including arrays passed by value to functions, share that slot. The same `unset()` is the standard fix after a by-reference `foreach`.
  • Are PHP objects passed by reference?
    No. A variable holds an object handle, and assigning or passing it copies the handle by value. Both copies reach the same object, so property changes are visible through either, but assigning a new object to one variable does not change the other. With a real reference, `$b = &$a;`, reassigning `$b` would change `$a` too.

saying these in an interview costs you the question

  • $b = &$a makes $b point to $a, like a C pointer.
  • unset($a) destroys the value that a reference $b still uses.
  • Copying an array always produces a fully independent array.
  • PHP passes objects by reference.
  • A normal assignment from a reference creates another reference.