Arrays: lists and lookup tables
One type, two habits — a numbered list and a keyed table — plus count, foreach, and the difference between an array and a fact.
One type, two shapes
A PHP array is an ordered map: values, each with a key. Written as a list — [1, 2, 3] — the keys are the numbers 0, 1, 2. Written with names — ['name' => 'Ada', 'role' => 'engineer'] — the keys are the strings you chose. Both are the same type, and both are made with square brackets.
The numbered shape is for things in an order: rows, scores, names. The keyed shape is for things with parts: a record, a settings block, one row of a result set. When data has names, using the names is what makes the code readable three weeks later.
Keys are not just labels; they are the lookup. $user["name"] finds the value by the key, and the order of the keys is the order you wrote them. That is why a record built in one place can be printed in another without a schema: the names travel with the data. The cost is that a typo in a key is not caught by the language, only by isset() or a warning at the point of reading.
Foreach, and counting
foreach ($list as $item) visits each value in order, without index arithmetic and without an off-by-one waiting to happen. When the keys matter, ask for them: foreach ($user as $key => $value). That is the loop shape you will write more than every other loop combined.
count($list) is the length. [] = value pushes onto the end, array_push does the same and is rarely needed, array_pop and array_shift take from the ends, and in_array($needle, $list, true) asks whether a value is present — the third argument turning on the strict comparison from the decisions chapter.
Nesting, and looking inside
Arrays hold arrays: a list of rows, each row a keyed record, is the most common data structure in any application. Reading it is not a new skill — it is a foreach around a foreach, or one key into another: $orders[0]['total'].
print_r($value) (or var_export) prints an entire structure in a readable form, which is the fastest way to answer "what is actually in this thing". The corrupt-looking first entry of every PHP array comes from that output — it is a debugging format, not data.
Reading a nested array
A table of records is read from the outside in. $orders[0] is the first record; $orders[0]["total"] is one field of it. In a loop, the index is implicit: foreach ($orders as $order) gives you a record, and $order["total"] gives you the field. Two levels of brackets is normal; three is a sign that the structure deserves a name.
When a level might be missing, check before reading. isset($order["total"]) answers whether the key exists and is not null; array_key_exists("total", $order) answers whether the key exists at all, even with a null value. Reading a key that is absent is a warning and a null, not a crash, which is why the mistake can travel a long way before anyone notices.
A list, a record, and a table of records
<?php
// A numbered list.
$scores = [88, 92, 79];
$scores[] = 95; // push one more on the end
echo 'Count: ' . count($scores) . PHP_EOL;
echo 'First: ' . $scores[0] . ' Last: ' . $scores[count($scores) - 1] . PHP_EOL;
// A record: values with names.
$user = [
'name' => 'Ada',
'role' => 'engineer',
'active' => true,
];
foreach ($user as $key => $value) {
echo str_pad($key, 8) . $value . PHP_EOL;
}
// A table: a list of records.
$orders = [
['item' => 'lamp', 'total' => 24.5],
['item' => 'chair', 'total' => 89.0],
];
$sum = 0;
foreach ($orders as $order) {
echo $order['item'] . ': ' . number_format($order['total'], 2) . PHP_EOL;
$sum = $sum + $order['total'];
}
echo 'Sum: ' . number_format($sum, 2) . PHP_EOL;
echo in_array('chair', array_column($orders, 'item'), true) ? 'Chair found.' : 'No chair.' . PHP_EOL;A library shelf
Run it and follow the three structures. Then add a fourth book, push your own title onto the list, and print the average rating with number_format.
Reading a key that does not exist is a warning and a null, never an empty string. isset($row['total']) asks whether a key is there — the question to ask before using one.
Keys, order, and copies
An array is an ordered map, not a special list type. [10, 20] uses the keys 0 and 1; ["name" => "Ada"] uses the key you chose. Insertion order is preserved, so foreach visits a record in the order it was written. A key can be an integer or a string, and PHP converts numeric-looking strings used as keys to integers, which is why "1" and 1 are the same key.
Assigning an array copies it, with the actual duplication deferred until one side changes. $copy = $rows; then $copy[] = $row; leaves $rows alone. unset() removes a key and leaves a gap, so the next [] does not reuse the number. isset() is false for a key whose value is null; array_key_exists() answers the narrower question of whether the key is there at all.
Three array mistakes are easy to make: reading a key before checking it, calling in_array() without the strict flag, and using isset() on a key that is present but null. isset($row["total"]), array_key_exists("total", $row) and in_array($x, $list, true) each ask a different question; pick the one you mean.
Try these next
- Build a keyed record for a book and print every field with
foreach ($book as $key => $value). - Add three rows to a shelf and total one numeric field across them.
- Create a key whose value is null and compare
isset()witharray_key_exists().
A pantry inventory
Run it and find the item that is not counted. Then add a low-stock marker to the output and change one threshold so another item becomes low.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What is the difference between [1, 2, 3] and ['a' => 1, 'b' => 2]?
