PHP has one array type that does two jobs. Give it numbers and it behaves like a list; give it strings and it behaves like a dictionary.
<?php
$fruits = ["apple", "banana", "mango"]; // indexed
$person = ["name" => "Ada", "age" => 36]; // associative
echo $fruits[0]; // apple
echo $person["name"]; // Ada
?>Adding and removing#
<?php
$fruits[] = "pear"; // append
array_push($fruits, "plum"); // same thing
array_unshift($fruits, "kiwi"); // add to the front
$last = array_pop($fruits); // remove and return the last
$first = array_shift($fruits); // remove and return the first
unset($fruits[1]); // remove by key — leaves a GAP
$fruits = array_values($fruits); // renumber 0,1,2...
?>That gap is worth knowing about. unset removes the key but does not renumber, so you can end up with keys 0, 2, 3. array_values() fixes it.
Checking what is there#
<?php
count($fruits); // how many
in_array("apple", $fruits); // is this value present?
array_search("apple", $fruits); // its key, or false
array_key_exists("name", $person); // is this key present?
isset($person["name"]); // present AND not null
empty($fruits); // false-y or missing
?>isset returns false for a key whose value is null; array_key_exists returns true. That difference causes real bugs when null is a meaningful value.
Transforming#
<?php
$prices = [100, 250, 80];
$withTax = array_map(fn($p) => $p * 1.2, $prices);
$big = array_filter($prices, fn($p) => $p > 90);
$total = array_reduce($prices, fn($sum, $p) => $sum + $p, 0);
$keys = array_keys($person);
$values = array_values($person);
$flipped = array_flip($person);
?>Sorting#
| Function | Sorts by | Keeps keys? |
|---|---|---|
sort |
Value | No — renumbers |
asort |
Value | Yes |
ksort |
Key | Yes |
usort |
Your comparison | No |
uasort |
Your comparison | Yes |
<?php
$users = [
["name" => "Ada", "age" => 36],
["name" => "Sam", "age" => 24],
];
usort($users, fn($a, $b) => $a["age"] <=> $b["age"]);
?>The <=> spaceship operator returns -1, 0 or 1 — exactly what a comparison function needs.
Combining#
<?php
$merged = array_merge($a, $b); // renumbers indexed keys
$merged = [...$a, ...$b]; // spread, PHP 8.1+
$merged = $a + $b; // keeps LEFT on key collision
?>The + operator is not addition here — it keeps whatever the left array already had for a duplicate key, which is occasionally what you want and usually a surprise.
Nested data#
This is the shape real data arrives in:
<?php
$orders = [
["item" => "pen", "price" => 50, "paid" => true],
["item" => "book", "price" => 300, "paid" => false],
];
$paidTotal = array_sum(
array_column(array_filter($orders, fn($o) => $o["paid"]), "price")
);
$names = array_column($orders, "item"); // ["pen", "book"]
$byItem = array_column($orders, "price", "item"); // ["pen" => 50, ...]
?>array_column is the one people do not know about and then use constantly.
When an array is the wrong tool#
- A fixed set of related fields — use a class.
$user["nmae"]is a silent bug;$user->nmaeis an error. - Very large numeric data —
SplFixedArrayuses less memory. - A queue or stack —
SplQueueandSplStacksay what they are.
Questions people ask#
Are PHP arrays really hash maps?
Yes — an ordered hash map underneath, which is why one type covers both lists and dictionaries and why insertion order is preserved.
Why does my JSON come out as an object?
Because the array’s keys are not sequential from zero, usually after array_filter or unset. Wrap it in array_values().
What is the difference between == and === for arrays?
== is true when they have the same key/value pairs; === also requires the same order and matching types.
How do I loop with the key?
foreach ($person as $key => $value).