0

Array declaration: [], array(), short syntax

Beginner5 min read·php-04-003

Concept

PHP offers two syntaxes for creating arrays: the array() language construct (available since PHP 4) and the short [] syntax (since PHP 5.4). They compile to identical opcodes — the choice is purely stylistic. Modern PHP codebases universally prefer []. Both create a HashTable initialized with the values you provide and grow dynamically as elements are added.

The short array syntax is particularly powerful for nested structures and multi-line declarations. PHP 7.1 extended the [] syntax to work in destructuring assignments (covered in its own lesson), making it the only array syntax you need to know in PHP 8.4. The array() construct remains valid and you will encounter it in legacy codebases — understanding both is important for reading older code.

Key detail about literal declaration: when you specify integer keys in a literal, PHP tracks the highest integer key seen so far. Subsequent push operations ($arr[] = value) use highest_seen_key + 1 as the next key, regardless of whether that key already exists. This means [5 => 'a', 'b'] produces [5 => 'a', 6 => 'b'] — the implicit key for 'b' is 5 + 1 = 6. This ordering of key tracking is evaluated left-to-right through the literal.

Nested array declarations are common for configuration, fixtures, and data pipelines. PHP imposes no depth limit syntactically, but deeply nested arrays become hard to maintain. Use named constants or builder patterns for configuration arrays that exceed three levels of nesting. For large datasets, consider reading from JSON or a database rather than hard-coding a large array literal — both for maintainability and to avoid PHP's memory overhead per element.

One practical detail: a trailing comma after the last element is valid and encouraged in PHP. It prevents diff noise when adding elements and is the PSR-12 recommended style for multi-line array literals.

Code Example

php
<?php
declare(strict_types=1);

// ---- Short syntax (preferred in PHP 8.4) ----
$empty   = [];
$indexed = [1, 2, 3];
$assoc   = ['key' => 'value', 'other' => 42];

// ---- Old array() syntax (legacy, avoid in new code) ----
$legacy = array(1, 2, 3);           // identical to [1, 2, 3]
$legacyAssoc = array('a' => 1);     // identical to ['a' => 1]

// ---- Key tracking in literals ----
$tracked = [5 => 'five', 'six', 'seven'];
// Keys: 5 => 'five', 6 => 'six', 7 => 'seven'
print_r($tracked);

$jumpy = [10 => 'a', 3 => 'b', 'c'];
// Keys: 10 => 'a', 3 => 'b', 11 => 'c'  (11 = max(10,3)+1 = 10+1)
print_r($jumpy);

// ---- Trailing comma is valid and encouraged ----
$config = [
    'host'     => 'localhost',
    'port'     => 5432,
    'database' => 'app',   // trailing comma — add new entries without modifying this line
];

// ---- Nested arrays ----
$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];
echo $matrix[1][2]; // 6

// ---- Mixed nested ----
$users = [
    ['id' => 1, 'name' => 'Alice', 'roles' => ['admin', 'editor']],
    ['id' => 2, 'name' => 'Bob',   'roles' => ['viewer']],
];

foreach ($users as $user) {
    echo $user['name'] . ': ' . implode(', ', $user['roles']) . PHP_EOL;
}

// ---- Dynamic array building (common pattern) ----
$result = [];
foreach (range(1, 5) as $n) {
    $result[] = $n * $n; // push — key = max_key + 1
}
// $result = [1, 4, 9, 16, 25]

// ---- Constant in array literal ----
const MAX_RETRIES = 3;
$settings = [
    'retries' => MAX_RETRIES,
    'timeout' => 30,
];

Interview Q&A

Q: You have an array literal [3 => 'a', 1 => 'b', 'c', 'd']. What are the keys of 'c' and 'd', and why?

PHP tracks the highest numeric key seen in the literal from left to right. After seeing key 3 for 'a' and key 1 for 'b', the highest integer key seen is 3. The next implicit key (for 'c') is therefore 3 + 1 = 4, and the one after that (for 'd') is 5. The result is [3 => 'a', 1 => 'b', 4 => 'c', 5 => 'd']. This behavior surprises developers who expect the implicit counter to track position in the literal rather than the maximum key value assigned so far.


Q: Is there a performance difference between declaring $arr = [] and then calling $arr[] = $x in a loop versus using array_fill() or range() for large arrays?

For large arrays where the final count is known upfront, range() and array_fill() are faster because they pre-allocate the HashTable capacity in a single C-level allocation, avoiding the repeated doubling reallocations that occur when pushing in a loop. In a loop, if you push 1,025 elements, the HashTable will have been resized roughly 7 times (8→16→32→...→2048), each resize copying all existing buckets. range(1, 1025) does this in one pass. For loops where the count is not known upfront, building with $arr[] = $x is fine and idiomatic.


Q: What is the difference between declaring an array as const RATES = [...] at file scope versus define('RATES', [...])? Which is available where?

const is a compile-time construct available only at class scope or at file scope outside any function or conditional. It cannot appear inside if blocks or function bodies at file scope in PHP. define() is a runtime function call and can appear anywhere — inside functions, conditionals, or loops. For arrays, both work since PHP 7.0. const is preferred at class scope and for module-level constants; define() is preferred when the constant name or value is determined at runtime. Class constants defined with const can be typed since PHP 8.3.