Arrays & Collections

Reviewed & published by Brayan K

By the end of this lesson you'll store many values in one variable — ordered lists, key-value records, and nested tables — and reshape them at will with PHP's array functions, the everyday workhorse of real applications.

Part of the free PHP course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Indexed Arrays — Ordered Lists

An array is a single variable that holds many values. The simplest kind is an indexed array — an ordered list where PHP labels each slot with a number starting at 0, not 1. You create one with the modern short syntax [ ] (older code uses array(...) — same thing). You read a slot by its index, and you tack a value onto the end with the handy $array[] = ... shortcut, which lets PHP pick the next number for you.

<?php
// An INDEXED array is an ordered list. Keys are numbers, starting at 0.
$fruits = ["Apple", "Banana", "Cherry"];   // [] is the short array syntax

echo $fruits[0] . "\n";          // Apple   — first item is index 0
echo $fruits[2] . "\n";          // Cherry  — third item is index 2
echo count($fruits) . "\n";      // 3       — how many items are in the array

// Add to the END with $array[] = ... (PHP picks the next number for you)
$fruits[] = "Date";               // now index 3 holds "Date"
echo count($fruits) . "\n";      // 4

// implode() joins every item into one string with a separator between them
echo implode(", ", $fruits) . "\n";   // Apple, Banana, Cherry, Date
?>

2️⃣ Associative Arrays — Key → Value

When position isn't meaningful but a label is, use an associative array. Instead of numbers, you choose your own keys — usually strings — and pair each with a value using the => arrow (read it as "points to"). This is how PHP models a record: a user, a config setting, a row from a database. You look values up by key, and assigning to a new key adds it while assigning to an existing key overwrites it.

<?php
// An ASSOCIATIVE array maps your OWN keys (usually strings) to values.
// Syntax: ['key' => 'value']  — the => arrow reads as "points to".
$person = [
    "name" => "Alice",
    "age"  => 28,
    "city" => "London",
];

echo $person["name"] . "\n";     // Alice  — look a value up BY its key
echo $person["age"] . "\n";      // 28

// Add or update by assigning to a key
$person["role"] = "Developer";    // new key
$person["age"]  = 29;             // overwrites the old value

// Inside "double quotes" wrap an array lookup in { } to print it cleanly
echo "{$person['name']} is {$person['age']}, role {$person['role']}\n";
// Alice is 29, role Developer
?>

Notice the {$person['name']} trick: inside a double-quoted string, wrapping an array lookup in curly braces lets PHP drop the value in cleanly. Without the braces, "$person['name']" confuses the parser.

3️⃣ Multidimensional Arrays & foreach

Because an array's values can themselves be arrays, you can build tables and nested structures — a list of records, a grid, JSON-shaped data. To walk through any array, reach for foreach: it hands you each element in turn without you tracking an index. To reach a nested value, stack the brackets: outer position, then inner key.

<?php
// A MULTIDIMENSIONAL array is an array whose values are themselves arrays.
// Here each row is an associative array describing one student.
$students = [
    ["name" => "Alice", "grade" => 95],
    ["name" => "Bob",   "grade" => 87],
    ["name" => "Cara",  "grade" => 92],
];

// foreach walks the list one row at a time; $s is the current inner array
foreach ($students as $s) {
    // Reach into a nested value with TWO sets of brackets
    echo "{$s['name']}: {$s['grade']}\n";
}

// Reach a single nested value directly: outer index, then inner key
echo "First student: {$students[0]['name']}\n";   // Alice
?>

4️⃣ Adding & Removing Items

Arrays are not fixed in size — you grow and shrink them as the program runs. Append with the $a[] = shortcut or array_push (which can add several at once); add to the front with array_unshift. Remove and capture the last item with array_pop or the first with array_shift. To delete one specific element by key, use unset — but note it leaves a gap in the numbering rather than renumbering.

<?php
$queue = ["Alice", "Bob"];

// --- ADDING ---
$queue[] = "Cara";                // append one item (shortest way)
array_push($queue, "Dan", "Eve"); // push one OR MORE onto the end
array_unshift($queue, "Zoe");     // add to the FRONT (everything shifts right)
echo implode(", ", $queue) . "\n";
// Zoe, Alice, Bob, Cara, Dan, Eve

// --- REMOVING ---
$last  = array_pop($queue);       // remove & RETURN the last item -> "Eve"
$first = array_shift($queue);     // remove & RETURN the first item -> "Zoe"
echo "Popped $last, shifted $first\n";

// unset() deletes a specific key (note: it does NOT renumber the rest)
unset($queue[1]);                 // removes "Bob"; indexes now 0, 2, 3...
echo implode(", ", $queue) . "\n";   // Alice, Cara, Dan
?>

5️⃣ Transforming Data — map, filter, reduce

The real power of PHP arrays is its library of built-in functions. Three are worth learning by heart. array_map applies a function to every element and returns a new array. array_filter keeps only the elements your test returns true for. array_reduce boils the whole array down to a single value (a sum, a max, a joined string). Watch the argument order — array_map(fn, array) but array_filter(array, fn). Alongside them, in_array, array_keys, array_values, and the string pair implode/explode cover most everyday needs.

<?php
$nums = [5, 2, 8, 1, 9, 3];

// array_map: TRANSFORM every item. Order: (callback, array). Returns a NEW array.
$doubled = array_map(fn($n) => $n * 2, $nums);
echo implode(", ", $doubled) . "\n";     // 10, 4, 16, 2, 18, 6

// array_filter: KEEP items where the callback is true. Order: (array, callback).
$evens = array_filter($nums, fn($n) => $n % 2 === 0);
echo implode(", ", $evens) . "\n";       // 2, 8 (both even numbers survive)

// array_reduce: BOIL the array down to ONE value. Order: (array, callback, start).
$total = array_reduce($nums, fn($carry, $n) => $carry + $n, 0);
echo "Sum: $total\n";                     // Sum: 28

// Membership & keys/values
echo in_array(8, $nums) ? "has 8\n" : "no 8\n";   // has 8
$prices = ["pen" => 2, "pad" => 5];
echo implode(", ", array_keys($prices)) . "\n";    // pen, pad
echo implode(", ", array_values($prices)) . "\n";  // 2, 5

// implode joins to a string; explode splits a string back into an array
$csv = implode("-", [2024, 6, 16]);        // "2024-6-16"
$parts = explode("-", $csv);               // ["2024", "6", "16"]
echo "$csv -> {$parts[1]}\n";             // 2024-6-16 -> 6
?>

Now you try. The script below is almost complete — fill in each ___ using the 👉 hint, then run it and check it against the Output panel.

<?php
// 🎯 YOUR TURN — fill in each blank marked ___ , then run it.

// 1) Make an indexed array of three colours
$colours = ___;            // 👉 e.g.  ["red", "green", "blue"]

// 2) Append "yellow" to the END using the [] shortcut
$colours___ = "yellow";    // 👉 put [] right after $colours

// 3) Print how many colours there are now
echo ___($colours) . "\n"; // 👉 the function that counts items

// 4) Join them into one line separated by ", "
echo ___(", ", $colours) . "\n";   // 👉 the function that joins to a string

// ✅ Expected output:
//    4
//    red, green, blue, yellow
?>

6️⃣ Sorting, Merging & Unpacking

sort reorders an indexed list ascending — but it renumbers the keys, so on an associative array it would throw your labels away. For keyed data use asort (by value) or ksort (by key); for a custom rule use usort with a comparison function. To combine arrays, use array_merge or the newer spread operator ...; and list() destructuring — written as [$x, $y] = [...] — unpacks an array straight into separate variables.

<?php
// sort() reorders an INDEXED array in place (ascending) and renumbers keys.
$nums = [5, 2, 8, 1];
sort($nums);
echo implode(", ", $nums) . "\n";         // 1, 2, 5, 8

// For ASSOCIATIVE arrays use asort()/ksort() so keys stay attached.
$scores = ["Bob" => 87, "Alice" => 95, "Cara" => 92];
asort($scores);                            // sort by VALUE, keep keys
echo implode(", ", array_keys($scores)) . "\n";   // Bob, Cara, Alice
ksort($scores);                            // sort by KEY (alphabetical)
echo implode(", ", array_keys($scores)) . "\n";   // Alice, Bob, Cara

// usort() sorts with YOUR rule. Return negative/zero/positive to order pairs.
$people = [["n" => "Al", "age" => 30], ["n" => "Bo", "age" => 22]];
usort($people, fn($a, $b) => $a["age"] - $b["age"]);  // youngest first
echo "{$people[0]['n']} is youngest\n";   // Bo is youngest

// Spread ... and list() destructuring
$more = [4, 5];
$all  = [1, 2, 3, ...$more];                // spread merges arrays: 1,2,3,4,5
echo implode(", ", $all) . "\n";          // 1, 2, 3, 4, 5
[$x, $y] = [10, 20];                        // list() unpacks into variables
echo "$x and $y\n";                        // 10 and 20
?>

One more. Build a small contact card as an associative array, then loop it with foreach ($arr as $key => $value), which hands you both halves of each pair.

<?php
// 🎯 YOUR TURN — build a contact card with an associative array.

// 1) Create an associative array with keys "name" and "email"
$contact = [
    "name"  => ___,        // 👉 a name in "double quotes"
    "email" => ___,        // 👉 an email in "double quotes"
];

// 2) Add a "city" key AFTER creating the array
$contact[___] = "Paris";   // 👉 the key name, in quotes

// 3) Loop over every key => value pair and print it
foreach ($contact as $key => $value) {
    echo "$key: $value\n";
}

// ✅ Expected output (example):
//    name: Sam
//    email: [email protected]
//    city: Paris
?>

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — PHP Arrays

Syntax / FunctionExampleWhat It Does
[ ]$a = [1, 2, 3];Create an array (short syntax)
=>["name" => "Al"]Map a key to a value
$a[] =$a[] = 4;Append to the end
unset()unset($a[1]);Delete one key (no renumber)
count()count($a)Number of items
in_array()in_array(2, $a)Is a value present? (bool)
array_map()array_map($fn, $a)Transform every element
array_filter()array_filter($a, $fn)Keep matching elements
array_reduce()array_reduce($a, $fn, 0)Boil down to one value
sort() / usort()usort($a, $cmp)Reorder (renumbers keys)
asort() / ksort()ksort($a)Sort, keeping keys
array_merge()array_merge($a, $b)Combine arrays
implode() / explode()implode(",", $a)Array ↔ string
... / [ ] =[...$a]; [$x] = $a;Spread / list() unpack

Mini-Challenge: Top Scorers

No code is filled in this time — just a brief and an outline. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments. This combines array_filter, usort, foreach and array_reduce — the real toolkit.

<?php
// 🎯 MINI-CHALLENGE: Top scorers report.
// No code is filled in — work from the steps, then run it.
//
// Starter data (copy this line in):
//   $students = [
//       ["name" => "Alice", "grade" => 95],
//       ["name" => "Bob",   "grade" => 62],
//       ["name" => "Cara",  "grade" => 88],
//       ["name" => "Dan",   "grade" => 74],
//   ];
//
// 1. Use array_filter to keep only students with grade >= 75 (the "passers").
// 2. Use usort to order the passers by grade, HIGHEST first.
//    (Tip: return $b['grade'] - $a['grade'] to sort descending.)
// 3. foreach over the result and echo "  <name>: <grade>" on its own line.
// 4. Use array_reduce (or a count + sum) to print the average of ALL grades.
//
// ✅ Expected output:
//    Alice: 95
//    Cara: 88
//    Average: 79.75

// your code here
?>

🎉 Lesson Complete!

Practice quiz

What index does the first element of an indexed array have?

  • 1
  • -1
  • 0
  • It has no index

Answer: 0. Indexed arrays start numbering at 0, so the first item is $arr[0].

What does $fruits[] = "Date" do?

  • Appends "Date" to the end of the array
  • Deletes the last item
  • Replaces index 0
  • Throws an error

Answer: Appends "Date" to the end of the array. The $arr[] = ... shortcut appends a value, letting PHP pick the next index.

Which symbol maps a key to a value in an associative array?

  • ->
  • :
  • ==
  • =>

Answer: =>. The => arrow links a key to its value, e.g. ["name" => "Alice"].

What does count() return for an array?

  • The largest value
  • The number of items
  • The last key
  • The sum of values

Answer: The number of items. count() returns how many elements the array holds.

Which has the array argument FIRST: array_map or array_filter?

  • array_filter
  • array_map
  • Both put it first
  • Neither takes an array

Answer: array_filter. It's array_map(fn, array) but array_filter(array, fn) — the array comes first in filter.

What does array_reduce do?

  • Removes duplicate items
  • Sorts the array
  • Boils the array down to a single value
  • Reverses the array

Answer: Boils the array down to a single value. array_reduce combines all elements into one value, like a sum or a max.

What does in_array(8, $nums) return?

  • The index of 8
  • A boolean (true/false)
  • The value 8
  • The array length

Answer: A boolean (true/false). in_array returns a boolean indicating whether the value exists in the array.

What happens to keys after sort() runs on an array?

  • Keys are kept as-is
  • String keys are preserved
  • It deletes all keys
  • It renumbers keys from 0

Answer: It renumbers keys from 0. sort() reindexes from 0, discarding existing keys — so don't use it on associative arrays you want keyed.

What does unset($queue[1]) do to the remaining numeric keys?

  • Renumbers them to fill the gap
  • Removes index 1 but leaves a gap (no renumber)
  • Deletes the whole array
  • Sorts the array

Answer: Removes index 1 but leaves a gap (no renumber). unset deletes that one key but does not renumber the rest, leaving a gap.

What does [1, 2, 3, ...$more] do when $more is [4, 5]?

  • Nests $more inside
  • Causes a syntax error
  • Spreads $more in, giving [1, 2, 3, 4, 5]
  • Adds the count of $more

Answer: Spreads $more in, giving [1, 2, 3, 4, 5]. The spread operator ... unpacks $more's elements into the new array: [1, 2, 3, 4, 5].

Continue this course

Frequently asked questions

What is the difference between an indexed and an associative array?

An indexed array uses automatic integer keys starting at 0 — it's an ordered list like ["a", "b", "c"]. An associative array uses keys you choose yourself, almost always strings, written with the => arrow: ["name" => "Alice"]. Under the hood PHP has only one array type — an ordered map — so a single array can even mix numeric and string keys, but for clarity you should pick one style per array.

Why does in_array() give a warning but array_search() returns a key?

They answer different questions. in_array(needle, haystack) returns a boolean — true or false — telling you whether a value exists. array_search(needle, haystack) returns the key of the first match, or false if nothing matches. Watch out: a match at index 0 returns 0, which is falsy, so test the result with === false (strict comparison) rather than a plain if when the key could legitimately be 0.

Why are the arguments to array_map and array_filter in a different order?

It is one of PHP's oldest inconsistencies. array_map(callback, array) takes the callback first, while array_filter(array, callback) takes the array first. There is no logic to it — you simply have to remember it (or let your editor remind you). array_reduce(array, callback, initial) follows array_filter's order and adds a starting value. Mixing the order up is one of the most common PHP array bugs.

When should I use sort() versus asort() or usort()?

Use sort() for a plain indexed list when you only care about the order of the values — it discards the old keys and renumbers from 0, so never use it on an associative array you want to keep keyed. Use asort()/arsort() to sort by value while keeping keys attached, and ksort()/krsort() to sort by key. Use usort() (and uasort/uksort) when you need a custom rule, such as sorting objects by a property: your callback returns a negative, zero, or positive number to order each pair.

What does the spread operator (...) do with arrays?

Inside an array literal, ...$other unpacks every element of $other into the new array, which is a clean way to merge: [1, 2, ...$more] gives a single flat array. In a function definition, function sum(...$nums) collects all extra arguments into one array. Since PHP 8.1 the spread operator also preserves string keys when merging associative arrays, behaving much like array_merge().