skip to content

Ordered Hash Map Model

A PHP array is an ordered hash map: keys are cast ("1" to 1, true to 1, floats truncated), insertion order is kept, and assignment copies the value. Interviewers use it to test your mental model.

part ofPHPoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In PHP, if you assign an array to another variable or pass it to a function and modify that copy, what happens to the original?

level: juniorimportance: must knowfreq 58%

answer

  1. arrays are values, not handles
  2. $b = $a then writing $b leaves $a
  3. functions get a copy unless &$param
  4. objects inside stay shared handles
  5. reference elements survive the copy

basics

~20 s

Nothing: PHP arrays are values, so assignment and by-value parameters give an independent copy, and changing it leaves the original intact. Objects stored inside are handles, so both copies still point to the same objects.

solid answer

~50 s

PHP arrays have **value semantics**. `$b = $a;` and passing `$a` to a normal parameter both give the receiver its own array; `$b[] = 4` or `$b['k'] = 'x'` never shows up in `$a`. To let a function modify the caller's array you must declare the parameter by reference (`array &$items`) or return the new array. The engine does not duplicate the data at the moment of assignment; it shares it until one side writes, so copying is cheap in practice. Two things are not deep-copied: **objects** stored in the array are handles, so `$b[0]->status = 'x'` is visible through `$a[0]`; and an element that is a PHP **reference** stays shared between the copies. Unlike languages where arrays or lists are reference types shared by every variable, a PHP array behaves like a string or an int.

code

php · 20 lines
php
<?php
function addDefault(array $cfg): void
{
    $cfg['debug'] = false;       // changes only the local copy
}

$cfg = ['env' => 'prod'];
addDefault($cfg);
var_dump(array_key_exists('debug', $cfg)); // bool(false)

final class Order
{
    public function __construct(public string $status) {}
}

$orders = [new Order('new')];
$copy = $orders;
$copy[] = new Order('new');       // original still has one element
$copy[0]->status = 'paid';        // same object behind both arrays
echo count($orders), ' ', $orders[0]->status; // 1 paid

go deeper

for a junior

Recall that arrays are copied on assignment and when passed to a normal parameter, so changes to the copy never reach the original.

for a middle

Explain returning versus &-parameters, why read-only passing is cheap, and why objects inside an array stay shared after the copy.

for a senior

Spot bugs from shared objects and leftover references in copied arrays, and avoid needless &-parameters added for imagined performance gains.

for a principal

Set conventions for mutability at API boundaries, preferring returned arrays or immutable value objects over in-place mutation across modules.

## Arrays are values In PHP an array behaves like a number or a string, not like an object. Assigning it or passing it to a function hands over a **value**, and the receiver can change its own array without affecting anyone else's: ```php $a = [1, 2, 3]; $b = $a; $b[] = 4; // $a is still [1, 2, 3] ``` The same holds at function boundaries. A parameter declared `array $items` receives a copy; appending, removing or overwriting elements inside the function changes only that copy. ## Getting changes back to the caller There are two idiomatic ways to let a function change an array the caller holds: 1. **Return it.** `function withDefaults(array $cfg): array { $cfg['debug'] ??= false; return $cfg; }` and the caller writes `$cfg = withDefaults($cfg);`. This is the usual choice in modern code because the data flow is visible at the call site. 2. **Take it by reference.** `function addDefaults(array &$cfg): void` lets the function write into the caller's variable directly. Several built-ins work this way, such as `sort()` and `array_push()`, which is why they return a status or count instead of the new array. ## Cheap copies Value semantics do not mean every assignment duplicates the data. The engine shares one array between variables and copies it only when one of them is about to be written, a technique described elsewhere as copy-on-write. For interview purposes the consequences are what matter: - passing a large array to a function that only reads it costs almost nothing; - the first write to a shared array triggers a full copy, which can be expensive for very large arrays inside loops; - taking a parameter by reference *to avoid a copy* is usually pointless and makes the code harder to reason about. ## What is not copied Value semantics apply to the array's own slots. What sits in those slots follows its own rules: | Element type | After `$b = $a` and a write through `$b` | |---|---| | scalar (int, string, bool, float) | independent; `$a` unchanged | | nested array | independent; nested arrays are values too | | object | **shared**: both arrays hold handles to the same object | | element bound by reference (`$x = &$a[0]` earlier) | **shared**: the reference is preserved in the copy | The object row is the most common surprise. Copying an array of entity objects and then calling setters on the copy changes the objects the original array points to, because only the handles were copied. To get independent objects you must `clone` each one. The reference row is rarer but nastier. The PHP manual warns that references inside arrays are preserved on normal assignment and when passing an array by value. A leftover reference, for example from an earlier `foreach ($a as &$v)` loop, can make a supposedly independent copy change the original. ## Contrast with reference-type collections In languages where arrays or lists are reference types, `b = a` makes two names for one collection, and a change through either is visible through both; getting an independent copy needs an explicit copy call. PHP chose the opposite default for arrays, while its objects follow the handle model. Interviewers ask this to see whether a candidate carries the other model into PHP code, for example expecting a function to fill an array passed to it without `&` or a return value. ## Practical checklist - Expect assignment and by-value parameters to isolate array changes. - Return modified arrays, or declare `&` deliberately when mutation in place is the point. - Remember that objects inside are shared, and clone them when you need independence. - `unset($v)` after any `foreach` by reference, so no reference lingers inside the array.

  • Should you pass a large array by reference to avoid copying it?
    Usually not. A by-value array is shared with the caller until one side writes, so a function that only reads it copies nothing. Declaring `&` just to save memory adds mutation risk without a real gain; use it only when changing the caller's array is the actual purpose.
  • How can a leftover reference make a copied array change the original?
    An element that is a PHP reference, for example left behind by `foreach ($a as &$v)` without `unset($v)`, stays a reference after `$b = $a`. Writing through that element in either array, or through `$v`, then changes the value both arrays see.

saying these in an interview costs you the question

  • Arrays are passed to functions by reference by default.
  • Assigning an array to a new variable duplicates its memory immediately.
  • Copying an array also clones the objects stored inside it.
  • A function can fill a caller's array parameter without & or a return value.
  • Passing big arrays by reference is the standard way to save memory.
open as a page

In PHP, what does it mean that an array is an ordered map, and how do indexed and associative arrays differ?

level: juniorimportance: must knowfreq 72%

basics

~20 s

A PHP array is one ordered map from int or string keys to values of any type. Indexed and associative arrays are the same type: an indexed array just has keys 0, 1, 2, and every array keeps insertion order.

open as a page

In PHP, how are array keys like "8", "08", true, 8.7 and null converted, and why do ZIP-code keys end up with mixed types?

level: middleimportance: must knowfreq 55%

basics

~20 s

A string key that is a canonical decimal integer, like "8" or "-8", is stored as int; "08" stays a string. true becomes 1, 8.7 becomes 8 and null becomes "", so ZIP code "90210" returns as int while "02134" stays string.

open as a page

In PHP, which key does $arr[] = $value assign, and why does it skip numbers after elements are unset?

level: middleimportance: should knowfreq 38%

basics

~20 s

$arr[] = $value uses one more than the largest integer key the array has held since it was last re-indexed, or 0 if it never had one. unset() does not lower that counter, so appended keys can skip numbers until array_values() re-indexes.

open as a page

In PHP 8.1 and later, what does array_is_list() check, and how does that relate to the engine's packed array layout?

level: seniorimportance: should knowfreq 25%

basics

~20 s

array_is_list(), added in PHP 8.1, returns true when the keys are exactly 0, 1, 2 and so on in iteration order, with no gaps or string keys. Packed layout is an internal memory optimisation; array_is_list() tests the keys, not the layout.

open as a page