Lesson 7 • Intermediate
Arrays & Collections 📦
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.
What You'll Learn in This Lesson
- Build indexed, associative, and multidimensional arrays with the [] short syntax
- Add and remove items with $a[] =, unset, and array_push/pop/shift/unshift
- Loop over arrays cleanly with foreach (including key => value)
- Search and inspect arrays with count, in_array, array_keys and array_values
- Transform data with array_map, array_filter, and array_reduce
- Sort, merge, join and split arrays — sort/usort/ksort, array_merge, implode/explode, spread ... and list()
$variable, use a foreach loop, and define a function. If any of those feel shaky, revisit Functions first.php file.php. The Output panel under each example shows exactly what to expect.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
?>Apple
Cherry
3
4
Apple, Banana, Cherry, Date2️⃣ 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
?>Alice
28
Alice is 29, role DeveloperNotice 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
?>Alice: 95
Bob: 87
Cara: 92
First student: Alice4️⃣ 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
?>Zoe, Alice, Bob, Cara, Dan, Eve
Popped Eve, shifted Zoe
Alice, Cara, Dan5️⃣ 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"; // 8 (only the 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
?>10, 4, 16, 2, 18, 6
8
Sum: 28
has 8
pen, pad
2, 5
2024-6-16 -> 6Now 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
?>4
red, green, blue, yellow___ blanks (a list, the [] append, then count and implode), then run it.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
?>1, 2, 5, 8
Bob, Cara, Alice
Alice, Bob, Cara
Bo is youngest
1, 2, 3, 4, 5
10 and 20One 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: sam@mail.com
// city: Paris
?>name: Sam
email: sam@mail.com
city: Paris___ blanks with a name, an email, and the "city" key. The loop prints each pair on its own line.Common Errors (and the fix)
- "Warning: Undefined array key 'email'" — you read a key that doesn't exist (a typo, or it was never set). PHP returns
nulland warns. Guard it withisset($a['email'])or supply a default with the null-coalescing operator:$a['email'] ?? 'none'. - array_map and array_filter take their arguments in opposite orders — it's
array_map(fn, $arr)butarray_filter($arr, fn). Swap them by mistake and you'll get a "TypeError: argument must be callable". When in doubt, the array comes second in map and first in filter/reduce. - Your keys vanished after sorting an associative array —
sort()(andrsort()) reindex from 0, discarding string keys. To keep key→value pairs intact, useasort()/arsort()to sort by value, orksort()to sort by key. - "PHP Parse error: syntax error, unexpected '=>'" — you used the
=>arrow outside an array, or mixed it up with assignment=. The arrow only links a key to a value inside array brackets or aforeach.
Pro Tips
- 💡 Reach for map/filter/reduce before writing a loop. They state your intent ("transform", "keep", "total") and avoid off-by-one bugs from manual indexing.
- 💡 Use
$a['key'] ?? $defaultwhenever a key might be missing — it's the clean, warning-free way to read optional data. - 💡 Pick one style per array. A purely indexed list or a purely associative record reads far clearer than one that mixes numeric and string keys.
📋 Quick Reference — PHP Arrays
| Syntax / Function | Example | What 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 |
Frequently Asked Questions
Q: 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.
Q: 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.
Q: 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.
Q: 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.
Q: 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().
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
?>usort, print each, then print the average of all grades.🎉 Lesson Complete!
- ✅ Indexed arrays are ordered lists keyed by numbers from
0; associative arrays map your own keys with=> - ✅ Arrays nest: a multidimensional array holds arrays, and
foreachwalks any of them - ✅ Grow and shrink with
$a[] =,array_push/pop/shift/unshift, andunset - ✅
array_map,array_filter, andarray_reducetransform, keep, and combine data (mind the argument order) - ✅
sortrenumbers keys; useasort/ksort/usortto keep or customise order - ✅
implode/explode, spread..., andlist()move data between arrays, strings, and variables - ✅ Next lesson: File Handling — read and write files on the server
Sign up for free to track which lessons you've completed and get learning reminders.