PHP Arrays Explained — Types, Syntax, and Common Mistakes
Every real application deals with lists. A shopping cart holds multiple products. A blog has multiple posts. A user profile stores multiple preferences. If PHP only let you store one value per variable, you'd be writing hundreds of lines just to hold a handful of items — and your code would collapse the moment the list grew or shrank. Arrays are how PHP solves this problem, and they're used in virtually every PHP script ever written.
The specific problem arrays fix is called 'data grouping'. Instead of writing $product1, $product2, $product3 and scrambling to keep track of them all, you write one $products array and let PHP manage the collection for you. You can add to it, remove from it, loop over it, sort it, search it — all with built-in tools PHP provides out of the box.
By the end of this article you'll know how to create all three types of PHP arrays (indexed, associative, and multidimensional), how to read and update values inside them, how to loop through them, and — crucially — the exact mistakes that trip up beginners so you can dodge them from day one.
Indexed Arrays — A Numbered List PHP Can Remember
An indexed array stores values in numbered slots, starting at position 0. Think of it like a numbered queue at a bakery: the first person is ticket 0, the second is ticket 1, and so on. The number is called the index or key, and the thing stored there is the value.
Why does counting start at 0? It's a convention inherited from low-level computing, and PHP follows it like almost every other language. It trips up beginners exactly once — then you never forget it.
You create an indexed array using the square-bracket syntax (preferred in modern PHP) or the older array() function. Both work, but square brackets are cleaner and what you'll see in professional codebases today.
To get a value out, you write the variable name followed by the index in square brackets: $fruits[0] gives you the first item. To add a new item to the end, use $fruits[] = 'mango' — the empty brackets tell PHP to append automatically. You don't need to know what the next index number is; PHP figures it out.
<?php // Create an indexed array of fruit names // PHP automatically assigns index 0, 1, 2 to each item $fruits = ['apple', 'banana', 'cherry']; // Access the first item — remember, counting starts at 0! echo $fruits[0]; // apple echo "\n"; // Access the third item using index 2 echo $fruits[2]; // cherry echo "\n"; // Add a new item to the END of the array // Empty [] tells PHP: 'put this at the next available index' $fruits[] = 'mango'; // Count how many items are in the array $totalFruits = count($fruits); echo "Total fruits: " . $totalFruits; // 4 echo "\n"; // Loop through every item using a foreach loop // $fruit (singular) is a temporary variable that holds each item one-by-one foreach ($fruits as $fruit) { echo "- " . $fruit . "\n"; } // Update an existing item — overwrite index 1 $fruits[1] = 'blueberry'; echo "Updated index 1: " . $fruits[1]; // blueberry echo "\n"; // Print the full array structure for debugging print_r($fruits);
cherry
Total fruits: 4
- apple
- banana
- cherry
- mango
Updated index 1: blueberry
Array
(
[0] => apple
[1] => blueberry
[2] => cherry
[3] => mango
)
Associative Arrays — Give Your Data a Meaningful Label
An indexed array is great for ordered lists, but what if you want to store a person's profile? You'd need to remember that index 0 is the name, index 1 is the email, index 2 is the age — and that's a disaster waiting to happen.
Associative arrays solve this by letting you choose your own keys instead of relying on numbers. Think of it like a form with labelled fields: 'Name: Sarah', 'Email: sarah@example.com', 'Age: 28'. Each label (key) maps directly to its value. This is how PHP stores structured data — user records, configuration settings, API responses.
You create an associative array using the same square-bracket syntax, but you define the key explicitly using the => arrow operator. On the left of => is the key (a string), on the right is the value.
Associative arrays are the backbone of most real PHP applications. When PHP reads a submitted HTML form, it hands you the data as an associative array in $_POST. When you decode a JSON API response, you get an associative array. When you fetch a database row with PDO, it comes back as an associative array. You'll use these constantly.
<?php // Create an associative array to store a user's profile // The string on the LEFT of => is the key // The value on the RIGHT of => is what's stored $userProfile = [ 'name' => 'Sarah', 'email' => 'sarah@example.com', 'age' => 28, 'country' => 'Canada' ]; // Access a value using its KEY — no index numbers needed echo $userProfile['name']; // Sarah echo "\n"; echo $userProfile['email']; // sarah@example.com echo "\n"; // Update a value — same syntax, just assign a new value $userProfile['age'] = 29; echo "Updated age: " . $userProfile['age']; // 29 echo "\n"; // Add a brand new key-value pair at any time $userProfile['role'] = 'editor'; // Loop through an associative array using foreach // $key holds the label, $value holds the data foreach ($userProfile as $key => $value) { echo $key . ': ' . $value . "\n"; } // Check if a specific key EXISTS before using it // This prevents errors when data might be missing if (array_key_exists('email', $userProfile)) { echo "Email is set: " . $userProfile['email'] . "\n"; } // Get all keys as a separate array $profileKeys = array_keys($userProfile); print_r($profileKeys);
sarah@example.com
Updated age: 29
name: Sarah
email: sarah@example.com
age: 29
country: Canada
role: editor
Email is set: sarah@example.com
Array
(
[0] => name
[1] => email
[2] => age
[3] => country
[4] => role
)
Multidimensional Arrays — Arrays Inside Arrays
So far each array has stored simple values — strings and numbers. But what if you want to store a list of users, and each user has their own profile data? You put arrays inside arrays. That's a multidimensional array, and it's less scary than it sounds.
Think of a spreadsheet. Each row is a user, each column is a piece of data (name, email, age). A multidimensional array works exactly the same way: the outer array is the list of rows, and each inner array is one row of data.
To access a value, you chain square brackets: $users[0]['name'] means 'go to the first user (index 0), then get the name key from their profile'. It reads left-to-right, outer-to-inner.
Multidimensional arrays are everywhere in PHP. Database query results return as an array of associative arrays. JSON from an API decodes into nested arrays. Shopping cart data is a list of product arrays. Once you're comfortable with one level of nesting, the rest follows the exact same logic — just add another bracket.
<?php // A list of users — each user is its own associative array // The outer array uses automatic numeric indexes (0, 1, 2) $users = [ [ 'name' => 'Alice', 'email' => 'alice@example.com', 'role' => 'admin' ], [ 'name' => 'Bob', 'email' => 'bob@example.com', 'role' => 'editor' ], [ 'name' => 'Carol', 'email' => 'carol@example.com', 'role' => 'viewer' ] ]; // Access a single value — outer index first, then inner key // Read as: "user at position 0, then their name" echo $users[0]['name']; // Alice echo "\n"; // Access Bob's email: position 1, key 'email' echo $users[1]['email']; // bob@example.com echo "\n"; // Loop through all users and display a formatted summary foreach ($users as $index => $user) { // $index is the numeric position (0, 1, 2) // $user is the full associative array for that person echo "User #" . ($index + 1) . ": " . $user['name']; echo " (" . $user['role'] . ")\n"; } // Add a brand new user to the list $users[] = [ 'name' => 'Dave', 'email' => 'dave@example.com', 'role' => 'editor' ]; echo "\nTotal users after adding Dave: " . count($users) . "\n"; // Update a nested value — change Carol's role $users[2]['role'] = 'admin'; echo "Carol's new role: " . $users[2]['role'] . "\n";
bob@example.com
User #1: Alice (admin)
User #2: Bob (editor)
User #3: Carol (viewer)
Total users after adding Dave: 4
Carol's new role: admin
The Most Useful PHP Array Functions You'll Actually Use
PHP ships with over 70 built-in array functions. You don't need to memorise all of them — but a handful come up in almost every project. Knowing these saves you from writing loops by hand for tasks PHP already solved.
Here's the honest shortlist: count() tells you how many items are in an array. in_array() checks whether a value exists anywhere in an array. array_push() adds items to the end (though the [] shorthand is more common). array_pop() removes and returns the last item. array_merge() combines two arrays into one. array_filter() removes items that don't pass a test. array_map() transforms every item using a function. sort() sorts an indexed array alphabetically or numerically. ksort() sorts an associative array by its keys.
The most important mental model: some functions return a new array (array_map, array_filter, array_merge) while others modify the original array in place (sort, ksort, array_push). This distinction matters — if you expect a sorted copy but get NULL because you forgot to use the return value, you'll be confused for longer than you should be.
<?php $temperatures = [22, 18, 31, 15, 27, 9, 34]; // --- count() --- // Returns the total number of items echo "Days recorded: " . count($temperatures) . "\n"; // 7 // --- in_array() --- // Returns true if the value exists somewhere in the array if (in_array(31, $temperatures)) { echo "31 degrees was recorded\n"; } // --- sort() --- // Sorts the array in place, lowest to highest // WARNING: this MODIFIES the original array — it does NOT return a new one sort($temperatures); echo "Sorted temperatures: "; echo implode(', ', $temperatures) . "\n"; // 9, 15, 18, 22, 27, 31, 34 // --- array_filter() --- // Keeps only the items where the callback returns true // Does NOT modify the original — returns a NEW array $hotDays = array_filter($temperatures, function($temp) { return $temp >= 25; // Keep only temperatures 25 and above }); echo "Hot days (25+): "; echo implode(', ', $hotDays) . "\n"; // 27, 31, 34 // --- array_map() --- // Transforms EVERY item using a function — returns a NEW array $celsiusTemps = [0, 20, 37, 100]; $fahrenheitTemps = array_map(function($celsius) { return ($celsius * 9/5) + 32; // Convert Celsius to Fahrenheit }, $celsiusTemps); echo "Fahrenheit: "; echo implode(', ', $fahrenheitTemps) . "\n"; // 32, 68, 98.6, 212 // --- array_merge() --- // Combines two arrays into one new array $morningReadings = [18, 19, 21]; $afternoonReadings = [28, 31, 29]; $allReadings = array_merge($morningReadings, $afternoonReadings); echo "All readings: "; echo implode(', ', $allReadings) . "\n"; // 18, 19, 21, 28, 31, 29 // --- array_pop() --- // Removes AND returns the last item — modifies the original array $lastReading = array_pop($allReadings); echo "Removed last reading: " . $lastReading . "\n"; // 29 echo "Remaining count: " . count($allReadings) . "\n"; // 5
31 degrees was recorded
Sorted temperatures: 9, 15, 18, 22, 27, 31, 34
Hot days (25+): 27, 31, 34
Fahrenheit: 32, 68, 98.6, 212
All readings: 18, 19, 21, 28, 31, 29
Removed last reading: 29
Remaining count: 5
| Feature | Indexed Array | Associative Array | Multidimensional Array |
|---|---|---|---|
| Key type | Auto-assigned integers (0, 1, 2...) | Custom strings or integers you define | Mix of both — outer and inner can differ |
| Best used for | Ordered lists with no named fields (e.g. a list of tags) | Structured records with named fields (e.g. user profile) | Collections of structured records (e.g. database rows) |
| Access syntax | $tags[0] | $user['email'] | $users[0]['email'] |
| Add new item | $tags[] = 'php' | $user['phone'] = '555-1234' | $users[] = ['name' => 'Eve'] |
| Loop style | foreach ($tags as $tag) | foreach ($user as $key => $value) | foreach ($users as $user) then access $user['key'] |
| Common real-world use | List of category names, image URLs | Form POST data, config settings, API response fields | Database result sets, JSON API responses, cart items |
🎯 Key Takeaways
- PHP has three practical array types — indexed (numbered slots), associative (named keys), and multidimensional (nested arrays) — and each solves a different data-storage problem.
- Indexed arrays start at 0, not 1. The last item in a 5-element array is at index 4. Getting this wrong is the single most common beginner bug.
- sort(), array_push(), and array_pop() modify the original array directly — they do not return a new copy. array_map() and array_filter() return new arrays and leave the original untouched.
- Always use array_key_exists() or isset() before accessing an associative array key you're not certain exists — silent NULL returns and PHP Warnings are far harder to debug than a proactive check.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Off-by-one index errors — Accessing $items[count($items)] instead of $items[count($items) - 1] to get the last item. Since arrays start at index 0, a 5-item array has a last index of 4, not 5. Accessing index 5 returns NULL and triggers a PHP Notice. Fix: use $items[count($items) - 1] or the built-in end($items) function which safely returns the last element without needing to know the index.
- ✕Mistake 2: Forgetting that sort() modifies the original array in place — Beginners write $sorted = sort($prices) expecting a sorted copy in $sorted. Instead, $sorted gets true (the boolean return value of sort), and $prices itself is now sorted. Fix: call sort($prices) on its own line with no assignment, then read from $prices. If you need to keep the original order intact, copy the array first with $sortedPrices = $prices; sort($sortedPrices);
- ✕Mistake 3: Using == instead of === when searching arrays — in_array('1', [1, 2, 3]) returns true with loose comparison (==) because PHP coerces the string '1' to the integer 1. This causes phantom matches that are very hard to debug. Fix: always pass true as the third argument — in_array('1', [1, 2, 3], true) — to enable strict type-safe comparison. It returns false because a string is not strictly equal to an integer.
Interview Questions on This Topic
- QWhat's the difference between an indexed array and an associative array in PHP, and when would you choose one over the other?
- QIf you call sort() on an associative array in PHP, what happens to the keys — and what function would you use instead if you want to sort by key while preserving the key-value pairs?
- QWhat does array_map() return versus what does array_walk() return — and which one would you use if you need to transform every value in an array into a new array of results?
Frequently Asked Questions
What is the difference between array() and [] in PHP?
They do exactly the same thing — both create an array. The square bracket syntax [] was introduced in PHP 5.4 and is now the modern standard you'll see in every professional codebase. array() still works perfectly, but [] is shorter and cleaner. Use [] unless you're maintaining code on an ancient PHP version below 5.4.
How do I check if a value exists in a PHP array?
Use in_array($value, $array) for a simple existence check — it returns true or false. For associative arrays where you want to check if a KEY exists (not a value), use array_key_exists('keyName', $array) or isset($array['keyName']). The key difference: isset() also returns false if the key exists but its value is NULL, while array_key_exists() returns true in that case.
Why does PHP use 0 as the first index of an array instead of 1?
Zero-based indexing comes from how computer memory addressing works at a low level — the index represents an offset from the start of the data block, and the first item has no offset, so it's 0. PHP inherits this convention from C, as do JavaScript, Python, Java, and most other languages. It feels odd at first but becomes completely natural within a week of practice.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.