PHP · Beginner
Arrays in PHP
In short: A PHP array is an ordered map that works as a list when its keys are 0, 1, 2 and so on: [10, 20, 30]. Read an element with $a[0], append with $a[] = $value, count with count($a) and walk it with foreach. Arrays are values: assigning or passing one makes an independent copy. Arrays with string keys are covered in the lesson on associative arrays.
One structure for lists and more
PHP has a single array type that covers what other languages split into lists, maps and stacks. Under the surface every array maps keys to values and remembers insertion order. When you write ["pear", "fig"] the keys are assigned automatically as 0 and 1, and the array behaves as a list; this lesson is about that use. Arrays whose keys are strings are the subject of the associative arrays lesson.
Read an element with its index in square brackets, starting from 0. Reading an index that does not exist yields null and a warning, so the last element of a list is $a[count($a) - 1], not $a[count($a)]. Assign to an index to replace an element. The shortest way to append is $a[] = $value, which uses the next integer key; array_push($a, $x, $y) appends several at once. array_pop removes and returns the last element, array_shift the first, and array_unshift inserts at the front. count($a) gives the number of elements.
foreach ($a as $value) visits every element in order; foreach ($a as $index => $value) also gives the key. Inside the loop $value is a copy, so assigning to it does not change the array. A for loop with an index is only needed when you must count or step differently.
Arrays are copied on assignment and when passed to a function. $b = $a; $b[] = 1; leaves $a unchanged. This is a real difference from languages where lists are references, and it is why a function that wants to change the caller's array must either return the new array or take a & reference parameter. (Internally PHP shares the storage until one side writes, so the copy is cheap.)
Removing with unset($a[1]) deletes the element but leaves the other keys as they were, so the array now has keys 0 and 2 and is no longer a tidy list. array_values($a) renumbers it. json_encode shows the difference at a glance: a list prints as [4,2], an array with gaps as {"0":4,"2":2}.
A few functions do most everyday list work. in_array($needle, $a) answers whether a value is present; array_search returns its index or false. array_sum, max and min summarise numbers. array_slice($a, $start, $length) extracts a run. implode(", ", $a) joins elements into a string and explode splits one. array_map($fn, $a) builds a new array by applying a function to each element, and array_filter($a, $fn) keeps the elements for which the function returns true, preserving their keys. Arrays can nest: $grid[1][2] reads row 1, column 2 of an array of arrays.
Syntax
$list = ["pear", "fig", "plum"]; // keys 0, 1, 2
$empty = [];
$first = $list[0];
$last = $list[count($list) - 1];
$list[1] = "date"; // replace
$list[] = "lime"; // append with the next key
array_push($list, "kiwi", "apple");
$gone = array_pop($list); // remove last
foreach ($list as $item) { ... }
foreach ($list as $i => $item) { ... }
count($list); in_array("fig", $list); array_search("fig", $list);
array_sum($nums); max($nums); min($nums);
array_slice($list, 1, 2); array_reverse($list);
implode(", ", $list); explode(",", "a,b,c");
array_map(fn($x) => $x * 2, $nums);
array_filter($nums, fn($x) => $x > 10);
$grid = [[1, 2], [3, 4]]; $grid[1][0]; // 3Indexes start at 0. unset() leaves a gap; array_values() renumbers.
Building and reading a list
A bike repair shop keeps its queue of jobs in an array, appends new ones, takes the first, and lists the rest.
<?php
$queue = ["bike 41", "bike 17"];
$queue[] = "bike 88";
array_push($queue, "bike 5", "bike 62");
echo count($queue), " jobs waiting\n";
echo "First: ", $queue[0], "\n";
echo "Last: ", $queue[count($queue) - 1], "\n";
$next = array_shift($queue);
echo "Now working on ", $next, "\n";
foreach ($queue as $position => $job) {
echo $position + 1, ". ", $job, "\n";
}Output
5 jobs waiting First: bike 41 Last: bike 62 Now working on bike 41 1. bike 17 2. bike 88 3. bike 5 4. bike 62
Two elements come from the literal, one from $queue[] and two from array_push, giving five. The last element sits at index 4, which is count - 1. array_shift removes the front element and, for a list, renumbers the rest from 0, so the foreach keys run 0 to 3 and adding 1 gives a human-friendly position.
Reading numbers into an array and summarising
The first input line says how many parcel weights follow; the program collects them and reports totals.
<?php
$n = (int) trim(fgets(STDIN));
$weights = [];
for ($i = 0; $i < $n; $i++) {
$weights[] = (float) trim(fgets(STDIN));
}
echo "Total: ", array_sum($weights), "\n";
echo "Heaviest: ", max($weights), "\n";
echo "Average: ", round(array_sum($weights) / count($weights), 2), "\n";
$heavy = array_filter($weights, fn($w) => $w > 10);
echo "Over 10 kg: ", count($heavy), "\n";
echo implode(" | ", $weights), "\n";Input given to the program: 4 ↵ 12.5 ↵ 8 ↵ 10 ↵ 15.25
Output
Total: 45.75 Heaviest: 15.25 Average: 11.44 Over 10 kg: 2 12.5 | 8 | 10 | 15.25
The loop runs exactly $n times, appending one converted value per pass; this is the standard way to read a known number of items. array_filter receives an arrow function and returns only the elements over 10, so counting the result answers the question. implode joins the floats with a separator; 8 and 10 print without decimals because they are whole.
Copies, gaps and transformations
Assigning an array copies it, unset leaves a hole, and array_map builds a new array from an old one.
<?php
$prices = [4, 9, 2];
$copy = $prices;
$copy[] = 7;
echo count($prices), " vs ", count($copy), "\n";
unset($prices[1]);
echo json_encode($prices), "\n";
$prices = array_values($prices);
echo json_encode($prices), "\n";
$doubled = array_map(fn($p) => $p * 2, $copy);
echo implode(",", $doubled), "\n";
echo in_array(9, $copy) ? "9 found" : "9 missing", "\n";
var_dump(array_search(7, $copy));
echo json_encode(array_slice($copy, 1, 2)), "\n";Output
3 vs 4
{"0":4,"2":2}
[4,2]
8,18,4,14
9 found
int(3)
[9,2]Appending to $copy does not touch $prices, which still has three elements. After unset($prices[1]) the keys are 0 and 2, and json_encode has to print it as an object to preserve them; array_values restores a list. array_map leaves $copy alone and returns the doubled values. array_search finds 7 at index 3, and array_slice takes two elements starting at index 1.
Common mistakes
Reading one past the end
Why it goes wrong:
$a[count($a)]does not exist because indexes start at 0. PHP prints a warning and givesnull, and any arithmetic on it treats it as 0.Fix: Use
$a[count($a) - 1],end($a)or$a[array_key_last($a)].Assuming unset renumbers the array
Why it goes wrong: After
unset($a[0])the first element has key 1;$a[0]is undefined and aforloop from 0 tocount - 1misses the last element.Fix: Call
array_valuesafter removing elements, or remove witharray_splice, or useforeach, which ignores gaps.PHP · fix<?php $a = ["x", "y", "z"]; unset($a[0]); $a = array_values($a); echo $a[0], "\n"; // yExpecting a function to change the array it received
Why it goes wrong: Arrays are passed by value.
function add(array $a) { $a[] = 1; }changes a copy, and the caller's array is unchanged.Fix: Return the modified array and assign it, or declare the parameter as
array &$a.Leaving a reference alive after foreach by reference
Why it goes wrong: After
foreach ($a as &$v),$vstill points at the last element, and a later loop that assigns to$voverwrites that element.Fix: Call
unset($v)right after the loop, or avoid&and build a new array witharray_map.
Everyday array functions
| Function | Does | Returns |
|---|---|---|
| count($a) | number of elements | int |
| in_array($x, $a) | is $x present | bool |
| array_search($x, $a) | index of $x | int or false |
| array_sum($a) / max($a) / min($a) | summaries of numbers | number |
| array_slice($a, $i, $len) | a run of elements | new array |
| array_map($fn, $a) | apply $fn to each | new array, same keys |
| array_filter($a, $fn) | keep elements where $fn is true | new array, original keys |
| implode($sep, $a) | join into text | string |
| array_values($a) | renumber from 0 | new array |
Where you use this
Most exercises hand you a sequence of values and ask for something about the whole: the sum, the largest, how many pass a test, or the same values transformed. The pattern is always the same: read the values into an array, then use array_sum, max, array_filter or array_map rather than tracking running totals by hand. Reading everything first also lets you make two passes, for example finding the average and then counting how many values are above it, which a single streaming loop cannot do.
$lines = [];
while (($line = fgets(STDIN)) !== false) {
$lines[] = (int) trim($line);
}
$avg = array_sum($lines) / count($lines);
echo count(array_filter($lines, fn($v) => $v > $avg)), "\n";Key points
[a, b, c]creates a list with keys 0, 1, 2;$a[i]reads and writes;$a[] = xappends.countgives the size; the last index iscount - 1.foreachvisits elements in order, optionally with their keys.- Assigning or passing an array copies it; use
&or return a new array to change the caller's. unsetleaves gaps;array_valuesrenumbers.array_maptransforms,array_filterselects,array_sum/max/minsummarise,implodejoins.- Arrays nest:
$grid[row][col].
Try it yourself
The program reads a count and then that many integers into $nums, then prints them in the order given. Change the last line so it prints them in reverse order, separated by single spaces.
<?php
$n = (int) trim(fgets(STDIN));
$nums = [];
for ($i = 0; $i < $n; $i++) {
$nums[] = (int) trim(fgets(STDIN));
}
echo implode(" ", $nums), "\n";
3 ↵ 5 ↵ 1 ↵ 99 1 5<?php
$n = (int) trim(fgets(STDIN));
$nums = [];
for ($i = 0; $i < $n; $i++) {
$nums[] = (int) trim(fgets(STDIN));
}
echo implode(" ", array_reverse($nums)), "\n";
Practise this
- Longest dry stretch within a rainfall budgetHard
Find the longest run of consecutive days whose total rainfall stays within a budget. A sliding window (two pointers) exercise in PHP.
ArraysNot started
- Parcel weights summaryEasy
Read a line of parcel weights into a PHP array and print the total and the heaviest one using explode, array_sum and max.
ArraysNot started
Related lessons
- Conditions and Loops in PHPBranch with if, elseif, else and match, repeat with while, for and foreach, and control loops with break and continue, with PHP 8 examples that read input.9 min
- Functions in PHPDefine PHP functions with typed parameters and return types, use default values, named arguments and variadics, and see why variables inside a function are.10 min
- Associative Arrays and Sorting in PHPUse string keys to model records in PHP, check keys safely, tally and group data, and sort by value, key or a custom rule with sort, asort, ksort and usort.10 min
Frequently asked questions
Is a PHP array a list or a map?
Both. Every PHP array is an ordered map from keys to values. When the keys are 0, 1, 2 and so on it behaves as a list, and functions such as array_push and json_encode treat it as one. When the keys are strings, or integers with gaps, it behaves as a map. array_is_list($a) (PHP 8.1) tells you which case you have.
How do I check whether a PHP array is empty?
count($a) === 0 is explicit; empty($a) and !$a also work because an empty array is false in a condition. Note that [0] and [null] are not empty: they contain one element.
How do I remove an element from a PHP array?
unset($a[$i]) removes the element with that key and leaves the other keys unchanged, so follow it with array_values($a) when you need a list. array_splice($a, $i, 1) removes and renumbers in one step. array_pop and array_shift remove from the ends. To remove by value, find the key with array_search first, or use array_filter to build a new array without it.
How this page was checked. Every program on it was run with PHP 8.4 at build time by the publishing checks, and the output shown is what it printed. Running PHP inside the browser is not available yet, so the Run button is absent rather than pretending; copy the code and run it with PHP 8.4 locally.