data types and standard library
Arrays
PHP arrays are used for lists, maps, and lightweight records, so the first skill is recognising the shape of the data before choosing a function.
You already met basic arrays in the PHP language track. This lesson focuses on the standard-library functions you will use when data has already arrived from a request, database query, API response, CSV file, or configuration file.
Start with the array shape
A list uses numeric positions:
<?php
declare(strict_types=1);
$productNames = ['keyboard', 'mouse', 'monitor'];
echo $productNames[0] . PHP_EOL;
// Prints:
// keyboard
A map uses meaningful keys:
<?php
declare(strict_types=1);
$stockBySku = [
'KB-101' => 12,
'MS-202' => 0,
];
echo $stockBySku['KB-101'] . PHP_EOL;
// Prints:
// 12
A list of records is usually an array of associative arrays:
<?php
declare(strict_types=1);
$orders = [
['id' => 1, 'status' => 'paid', 'total' => 1250],
['id' => 2, 'status' => 'draft', 'total' => 800],
];
echo $orders[0]['status'] . PHP_EOL;
// Prints:
// paid
Many array bugs come from treating one shape as another. Before you reach for array_map() or array_column(), ask: is this a plain list, a keyed map, or a list of records?
Pulling a column from records
array_column() is useful when you have a list of records and need one field from each record.
<?php
declare(strict_types=1);
$orders = [
['id' => 1, 'status' => 'paid', 'total' => 1250],
['id' => 2, 'status' => 'paid', 'total' => 800],
];
$totals = array_column($orders, 'total');
$grandTotal = array_sum($totals);
echo 'Grand total: ' . $grandTotal . ' pennies' . PHP_EOL;
// Prints:
// Grand total: 2050 pennies
This is common after fetching rows from a database or decoding JSON. The code is short, but it only makes sense if every record is expected to contain a total key.
Filtering rows
array_filter() keeps values that pass a test. When filtering a list, call array_values() afterwards if you need a clean zero-based list.
<?php
declare(strict_types=1);
$orders = [
['id' => 1, 'status' => 'paid', 'total' => 1250],
['id' => 2, 'status' => 'draft', 'total' => 800],
['id' => 3, 'status' => 'paid', 'total' => 2199],
];
$paidOrders = array_values(array_filter($orders, function (array $order): bool {
return $order['status'] === 'paid';
}));
echo count($paidOrders) . ' paid orders' . PHP_EOL;
// Prints:
// 2 paid orders
array_filter() preserves the original keys. That is useful for maps, but it can surprise you with lists because the first remaining item may no longer be at index 0.
Mapping values
array_map() transforms each value and returns a new array. Use it when you want the same operation applied to each item.
<?php
declare(strict_types=1);
$names = ['keyboard', 'mouse', 'monitor'];
$labels = array_map(function (string $name): string {
return ucfirst($name);
}, $names);
echo implode(', ', $labels) . PHP_EOL;
// Prints:
// Keyboard, Mouse, Monitor
Mapping should not normally change external state. If the callback is sending emails, writing files, or updating a database, a foreach loop is usually clearer.
Reducing values
array_reduce() turns an array into one final value.
<?php
declare(strict_types=1);
$lines = [
['quantity' => 2, 'unitPrice' => 500],
['quantity' => 1, 'unitPrice' => 1299],
];
$total = array_reduce(
$lines,
function (int $carry, array $line): int {
return $carry + ($line['quantity'] * $line['unitPrice']);
},
0
);
echo 'Basket total: ' . $total . ' pennies' . PHP_EOL;
// Prints:
// Basket total: 2299 pennies
array_reduce() is useful for totals, summaries, and grouped values. If the callback becomes hard to read, write a small named function or use a foreach loop instead.
Sorting arrays
Different sort functions preserve different things. sort() reindexes values, while asort() preserves keys.
<?php
declare(strict_types=1);
$stockBySku = [
'KB-101' => 12,
'MS-202' => 3,
'MN-303' => 8,
];
asort($stockBySku);
foreach ($stockBySku as $sku => $stock) {
echo $sku . ': ' . $stock . PHP_EOL;
}
// Prints:
// MS-202: 3
// MN-303: 8
// KB-101: 12
Choose the sorting function based on whether the keys matter. Product IDs, slugs, and database IDs usually matter.
Merging arrays
array_merge() appends numeric-keyed values and lets later string-keyed values replace earlier ones.
<?php
declare(strict_types=1);
$defaults = [
'currency' => 'GBP',
'perPage' => 20,
];
$requestOptions = [
'perPage' => 50,
];
$options = array_merge($defaults, $requestOptions);
echo $options['currency'] . ' ' . $options['perPage'] . PHP_EOL;
// Prints:
// GBP 50
This is useful for options and configuration. Be careful when the arrays contain numeric keys, because merging a list is different from replacing named options.
Handling missing keys
Do not assume a key exists when data comes from outside your code. Check it at the boundary and fail with a useful message.
<?php
declare(strict_types=1);
function requireOrderTotal(array $order): int
{
if (!array_key_exists('total', $order)) {
throw new InvalidArgumentException('Order total is required.');
}
if (!is_int($order['total'])) {
throw new InvalidArgumentException('Order total must be an integer.');
}
return $order['total'];
}
echo requireOrderTotal(['id' => 1, 'total' => 1250]) . PHP_EOL;
// Prints:
// 1250
Use array_key_exists() when null is a possible value and you need to know whether the key exists. Use isset() when null should behave like a missing value.
What to remember
Arrays are flexible, but that flexibility is also the risk. Name variables after the shape they contain, such as $paidOrders, $stockBySku, or $totals. Validate records from external sources before transforming them. Prefer readable loops when nested array functions become difficult to explain in a code review.
Practice
Task: Build an order summary
Build a small order summary from an array of order records.
Requirements
- Use
declare(strict_types=1);. - Start with an array containing at least three orders.
- Each order should contain
id,status, andtotal. - Keep only orders with the status
paid. - Reindex the filtered list.
- Pull the paid order IDs into their own array.
- Pull the paid totals into their own array and sum them.
- Print the paid order IDs and the grand total.
- Include the expected output as comments in the same PHP code block.
The finished example should make it clear when you are filtering records, when you are extracting columns, and when you are calculating the final total.
Show solution
<?php
declare(strict_types=1);
$orders = [
['id' => 1, 'status' => 'paid', 'total' => 1250],
['id' => 2, 'status' => 'draft', 'total' => 800],
['id' => 3, 'status' => 'paid', 'total' => 2199],
];
$paidOrders = array_values(array_filter($orders, function (array $order): bool {
return $order['status'] === 'paid';
}));
$paidOrderIds = array_column($paidOrders, 'id');
$paidTotals = array_column($paidOrders, 'total');
$grandTotal = array_sum($paidTotals);
echo 'Paid orders: ' . implode(', ', $paidOrderIds) . PHP_EOL;
echo 'Grand total: ' . $grandTotal . ' pennies' . PHP_EOL;
// Prints:
// Paid orders: 1, 3
// Grand total: 3449 pennies
This solution separates the work into clear stages. array_filter() chooses the records, array_values() turns the result back into a normal list, array_column() extracts the fields needed for output and calculation, and array_sum() produces the final total.