php language basics

Arrays

An array is a value that can hold many values. In PHP, the same array type is used for simple lists, key-value maps, and nested records. That flexibility is useful, but it also means you must be clear about the shape of the data.

Arrays appear everywhere in PHP: decoded JSON, request data, configuration, database rows, form errors, route parameters, grouped records, and small scripts. A junior developer needs to do more than create an array. You need to read values safely, check whether keys exist, add and remove items, loop over records, transform values, and sort data without losing track of the keys.

Lists And Keyed Arrays

A list uses numeric keys. PHP assigns the keys automatically when you append values.

PHP example
<?php

$tags = ['php', 'beginner'];
$tags[] = 'arrays';

print_r($tags);

// Prints:
// Array
// (
//     [0] => php
//     [1] => beginner
//     [2] => arrays
// )

A keyed array uses meaningful keys.

PHP example
<?php

$product = [
    'sku' => 'BOOK-001',
    'name' => 'PHP Workbook',
    'price_cents' => 2499,
    'in_stock' => true,
];

echo $product['name'] . " costs {$product['price_cents']} cents\n";

// Prints:
// PHP Workbook costs 2499 cents

Use keyed arrays when each value has a name. Use lists when order matters and each item has the same meaning.

Reading Optional Keys

Reading a missing key causes a warning. Decide what should happen when a key is missing.

PHP example
<?php

$product = [
    'name' => 'PHP Workbook',
    'price_cents' => 2499,
];

$currency = $product['currency'] ?? 'GBP';

echo $currency . "\n";

// Prints:
// GBP

Use ?? when a simple fallback is correct. Use array_key_exists() when you need to distinguish "the key is missing" from "the key exists but contains null".

PHP example
<?php

$product = ['discount_cents' => null];

var_dump(array_key_exists('discount_cents', $product));
var_dump(isset($product['discount_cents']));

// Prints:
// bool(true)
// bool(false)

isset() is false for null. array_key_exists() only asks whether the key exists.

Nested Arrays

Nested arrays let you represent records inside records.

PHP example
<?php

$order = [
    'id' => 1001,
    'customer' => [
        'name' => 'Amo',
        'email' => 'amo@example.com',
    ],
    'items' => [
        ['sku' => 'BOOK-001', 'quantity' => 2],
        ['sku' => 'PEN-002', 'quantity' => 1],
    ],
];

echo $order['customer']['email'] . "\n";
echo $order['items'][0]['sku'] . "\n";

// Prints:
// amo@example.com
// BOOK-001

Nested arrays are common after decoding JSON or fetching rows grouped by another value. The risk is assuming every nested key exists. Check at the boundary before relying on external data.

Adding, Updating, Removing, And Reindexing

Arrays are often changed in small steps.

PHP example
<?php

$tags = ['php', 'arrays'];

$tags[] = 'practice';
$tags[1] = 'array-basics';
unset($tags[0]);

print_r($tags);
print_r(array_values($tags));

// Prints:
// Array
// (
//     [1] => array-basics
//     [2] => practice
// )
// Array
// (
//     [0] => array-basics
//     [1] => practice
// )

unset() removes an item but does not renumber numeric keys. Use array_values() when you need a clean zero-based list afterward.

Checking Membership And Searching

Use in_array() to check whether a value appears in an array. Pass true as the third argument for strict comparison.

PHP example
<?php

$allowedStatuses = ['pending', 'paid', 'failed'];

var_dump(in_array('paid', $allowedStatuses, true));
var_dump(in_array('0', [0, 1, 2], true));

// Prints:
// bool(true)
// bool(false)

Use array_search() when you need the key where a value was found.

PHP example
<?php

$statuses = ['pending', 'paid', 'failed'];
$position = array_search('paid', $statuses, true);

var_dump($position);

// Prints:
// int(1)

Be careful: array_search() can return 0, which is a valid key but falsey. Compare the result with !== false.

Filtering, Mapping, And Walking

array_filter() keeps items that pass a check.

PHP example
<?php

$products = [
    ['name' => 'Notebook', 'in_stock' => true],
    ['name' => 'Pen', 'in_stock' => false],
    ['name' => 'Mug', 'in_stock' => true],
];

$inStock = array_filter($products, fn (array $product): bool => $product['in_stock']);

print_r(array_column($inStock, 'name'));

// Prints:
// Array
// (
//     [0] => Notebook
//     [2] => Mug
// )

array_filter() preserves keys. Use array_values() afterward if you need a reindexed list.

array_map() transforms each item and returns a new array.

PHP example
<?php

$prices = [1299, 2500, 999];

$labels = array_map(
    fn (int $cents): string => '£' . number_format($cents / 100, 2),
    $prices
);

print_r($labels);

// Prints:
// Array
// (
//     [0] => £12.99
//     [1] => £25.00
//     [2] => £9.99
// )

array_walk() is useful when you want to visit each item, often to modify values by reference.

PHP example
<?php

$names = [' ada ', ' grace '];

array_walk($names, function (string &$name): void {
    $name = trim($name);
});

print_r($names);

// Prints:
// Array
// (
//     [0] => ada
//     [1] => grace
// )

Use by-reference callbacks carefully. If returning a new array is clearer, prefer array_map().

Pulling Columns And Indexing Records

array_column() pulls one key from each nested array.

PHP example
<?php

$products = [
    ['sku' => 'BOOK-001', 'name' => 'PHP Workbook'],
    ['sku' => 'PEN-002', 'name' => 'Pen'],
];

$namesBySku = array_column($products, 'name', 'sku');

print_r($namesBySku);

// Prints:
// Array
// (
//     [BOOK-001] => PHP Workbook
//     [PEN-002] => Pen
// )

This pattern is common when you need fast lookup by ID, SKU, email, or another unique value.

Sorting

Use sort() for simple lists when you do not care about preserving keys. Use asort() when keys matter. Use usort() for custom comparison logic.

PHP example
<?php

$products = [
    ['name' => 'Notebook', 'price_cents' => 1299],
    ['name' => 'Mug', 'price_cents' => 899],
    ['name' => 'Backpack', 'price_cents' => 4200],
];

usort($products, fn (array $a, array $b): int => $a['price_cents'] <=> $b['price_cents']);

print_r(array_column($products, 'name'));

// Prints:
// Array
// (
//     [0] => Mug
//     [1] => Notebook
//     [2] => Backpack
// )

The spaceship operator <=> returns the comparison result that usort() expects.

Merging Settings

Arrays are often used for configuration. Later values can override defaults.

PHP example
<?php

$defaults = [
    'currency' => 'GBP',
    'items_per_page' => 20,
];

$userSettings = [
    'items_per_page' => 50,
];

$settings = array_merge($defaults, $userSettings);

print_r($settings);

// Prints:
// Array
// (
//     [currency] => GBP
//     [items_per_page] => 50
// )

For string keys, array_merge() lets later arrays override earlier arrays. Numeric keys behave differently because lists are reindexed.

Common Mistakes

Do not assume a key exists just because one example has it. External data can be missing, null, duplicated, wrongly typed, or shaped differently.

Do not use loose membership checks for security or status decisions. Use strict comparison with in_array() and array_search().

Do not forget that some array functions preserve keys and others reindex. If JSON output needs a list, reindex with array_values() after filtering.

What You Should Be Able To Do

After this lesson, you should be able to:

  • create lists, keyed arrays, and nested arrays;
  • read required and optional keys deliberately;
  • add, update, remove, and reindex values;
  • check membership and search by value;
  • filter, map, and walk arrays;
  • pull columns and build lookup arrays;
  • sort records by a field;
  • merge default settings with overrides.

Practice

Task: Product Summary

Task

Create a $product keyed array with sku, name, price_cents, and in_stock.

Print a summary in this format:

BOOK-001: PHP Workbook costs 2499 cents

Then read an optional currency key with a default of GBP and print it.

Show solution

Solution

PHP example
<?php

$product = [
    'sku' => 'BOOK-001',
    'name' => 'PHP Workbook',
    'price_cents' => 2499,
    'in_stock' => true,
];

$currency = $product['currency'] ?? 'GBP';

echo "{$product['sku']}: {$product['name']} costs {$product['price_cents']} cents\n";
echo "Currency: {$currency}\n";

// Prints:
// BOOK-001: PHP Workbook costs 2499 cents
// Currency: GBP

Explanation

The required fields are read directly. The optional currency field uses ?? because a simple fallback is correct for this exercise.

Task: Predict Array Keys

Task

Before running this code, predict both arrays printed by print_r().

PHP example
<?php

$tags = ['php', 'arrays', 'practice'];

unset($tags[1]);

print_r($tags);
print_r(array_values($tags));

Then run the code and compare the output with your prediction.

Show solution

Solution

PHP example
<?php

$tags = ['php', 'arrays', 'practice'];

unset($tags[1]);

print_r($tags);
print_r(array_values($tags));

// Prints:
// Array
// (
//     [0] => php
//     [2] => practice
// )
// Array
// (
//     [0] => php
//     [1] => practice
// )

Explanation

unset() removes the value but keeps the remaining numeric keys as they were. array_values() creates a new zero-based list.

Task: Build Order List

Task

Build an $order array with an id and an items list. Each item should have sku and quantity.

Loop over the items and print:

BOOK-001 x 2
PEN-002 x 1
Show solution

Solution

PHP example
<?php

$order = [
    'id' => 1001,
    'items' => [
        ['sku' => 'BOOK-001', 'quantity' => 2],
        ['sku' => 'PEN-002', 'quantity' => 1],
    ],
];

foreach ($order['items'] as $item) {
    echo "{$item['sku']} x {$item['quantity']}\n";
}

// Prints:
// BOOK-001 x 2
// PEN-002 x 1

Explanation

The order contains a nested list of items. foreach visits each item array and reads the sku and quantity keys.

Task: Update Product Tags

Task

Start with ['php', 'beginner'].

Write code that:

  • adds arrays only if it is not already present;
  • removes beginner;
  • reindexes the list;
  • prints the final tags.
Show solution

Solution

PHP example
<?php

$tags = ['php', 'beginner'];

if (!in_array('arrays', $tags, true)) {
    $tags[] = 'arrays';
}

$beginnerKey = array_search('beginner', $tags, true);

if ($beginnerKey !== false) {
    unset($tags[$beginnerKey]);
}

$tags = array_values($tags);

print_r($tags);

// Prints:
// Array
// (
//     [0] => php
//     [1] => arrays
// )

Explanation

in_array() prevents a duplicate tag. array_search() finds the key to remove. array_values() reindexes the list after unset().

Task: Sort And Index Products

Task

Given a list of products with sku, name, and price_cents:

  • sort the products by price from low to high;
  • print the sorted product names;
  • build $namesBySku using array_column();
  • print the lookup array.
Show solution

Solution

PHP example
<?php

$products = [
    ['sku' => 'BOOK-001', 'name' => 'PHP Workbook', 'price_cents' => 2499],
    ['sku' => 'MUG-002', 'name' => 'Mug', 'price_cents' => 899],
    ['sku' => 'BAG-003', 'name' => 'Backpack', 'price_cents' => 4200],
];

usort($products, fn (array $a, array $b): int => $a['price_cents'] <=> $b['price_cents']);

print_r(array_column($products, 'name'));

$namesBySku = array_column($products, 'name', 'sku');

print_r($namesBySku);

// Prints:
// Array
// (
//     [0] => Mug
//     [1] => PHP Workbook
//     [2] => Backpack
// )
// Array
// (
//     [MUG-002] => Mug
//     [BOOK-001] => PHP Workbook
//     [BAG-003] => Backpack
// )

Explanation

usort() changes the order of the product records. array_column($products, 'name', 'sku') builds a lookup where each SKU points to the product name.

Task: Merge And Print Settings

Task

Merge default settings with user settings.

Defaults:

  • currency is GBP;
  • items_per_page is 20;
  • show_tax is true.

User settings:

  • items_per_page is 50.

Print the merged settings.

Show solution

Solution

PHP example
<?php

$defaults = [
    'currency' => 'GBP',
    'items_per_page' => 20,
    'show_tax' => true,
];

$userSettings = [
    'items_per_page' => 50,
];

$settings = array_merge($defaults, $userSettings);

print_r($settings);

// Prints:
// Array
// (
//     [currency] => GBP
//     [items_per_page] => 50
//     [show_tax] => 1
// )

Explanation

For string keys, later arrays override earlier arrays. The user setting replaces the default items_per_page, while the other defaults remain.