Skip to main content

Strings & Arrays

Strings and arrays are two of the most used data types in PHP. You will work with them constantly - building messages, processing user input, storing lists of data, and transforming collections. This chapter gives you a solid foundation in both.

Strings​

You already met strings in chapter 2. Here we go deeper: concatenation, heredoc and nowdoc, and the most useful string functions.

String recap - single vs double quotes​

Recall from chapter 2:

  • Single quotes ('...'): Literal text. Variables and most escape sequences are not interpreted.
  • Double quotes ("..."): Variables are interpolated, and escape sequences like \n and \t work.
<?php

$name = 'Alice';

echo 'Hello, $name!'; // Output: Hello, $name! (literal)
echo "Hello, $name!"; // Output: Hello, Alice! (interpolated)

Tip: Use single quotes when you have plain text with no variables. Use double quotes when you need variable interpolation or escape sequences.

String concatenation​

The dot operator (.) joins strings together. You can chain it to build longer strings:

<?php

$first = 'Hello';
$second = 'World';
$greeting = $first . ', ' . $second . '!';

echo $greeting; // Output: Hello, World!

The concatenation assignment operator (.=) appends to an existing string:

<?php

$message = 'Hello';
$message .= ', ';
$message .= 'World';
$message .= '!';

echo $message; // Output: Hello, World!

This is useful when you build a string piece by piece in a loop or conditional:

<?php

$output = '';
$items = ['apple', 'banana', 'cherry'];

foreach ($items as $item) {
$output .= '- ' . $item . "\n";
}

echo $output;
// Output:
// - apple
// - banana
// - cherry

Heredoc and nowdoc syntax​

When you have long blocks of text with many variables, heredoc and nowdoc keep your code readable.

Heredoc behaves like double-quoted strings - variables are interpolated:

<?php

$name = 'Alice';
$role = 'Developer';

$text = <<<EOT
Hello, $name!

You have been assigned the role of $role.
Please complete the onboarding form by Friday.

Best regards,
The Team
EOT;

echo $text;

The closing identifier (EOT in this example) must be on its own line, at the start of the line, with no spaces before it, and followed by a semicolon. You can use any identifier - EOT, END, HTML, etc. - as long as it matches at the start and end.

Nowdoc behaves like single-quoted strings - no variable interpolation:

<?php

$template = <<<'EOT'
This is a literal string.
No $variables are expanded here.
Use nowdoc for templates or SQL that should stay exactly as written.
EOT;

echo $template;

The only difference is that the opening identifier is wrapped in single quotes: <<<'EOT'.

Note: Heredoc and nowdoc are especially useful for embedding HTML, SQL, or multi-line text without escaping quotes everywhere.

Common string functions​

PHP has dozens of string functions. Here are the ones you will use most often:

FunctionDescriptionExample
strlen($str)Number of bytes (not characters) in stringstrlen('Hello') → 5
strtolower($str)Convert to lowercasestrtolower('HELLO') → 'hello'
strtoupper($str)Convert to uppercasestrtoupper('hello') → 'HELLO'
trim($str)Remove whitespace from both endstrim(' hi ') → 'hi'
ltrim($str)Remove whitespace from leftltrim(' hi') → 'hi'
rtrim($str)Remove whitespace from rightrtrim('hi ') → 'hi'
str_replace($search, $replace, $str)Replace all occurrencesstr_replace('a', 'o', 'cat') → 'cot'
strpos($haystack, $needle)Position of first occurrence (or false)strpos('hello', 'l') → 2
substr($str, $start, $length)Extract a substringsubstr('hello', 1, 3) → 'ell'
explode($delimiter, $str)Split string into array by delimiterexplode(',', 'a,b,c') → ['a','b','c']
implode($glue, $arr)Join array elements into stringimplode('-', [1,2,3]) → '1-2-3'
str_contains($haystack, $needle)True if string contains substring (PHP 8+)str_contains('hello', 'ell') → true
str_starts_with($haystack, $needle)True if string starts with substring (PHP 8+)str_starts_with('hello', 'he') → true
str_ends_with($haystack, $needle)True if string ends with substring (PHP 8+)str_ends_with('hello', 'lo') → true
sprintf($format, ...$args)Build string from format and valuessprintf('Hi %s', 'Alice') → 'Hi Alice'

Examples:

<?php

$text = ' Hello, World! ';
echo strlen(trim($text)); // 13 (trimmed length)
echo strtolower($text); // " hello, world! "
echo str_replace('World', 'PHP', $text); // " Hello, PHP! "

$csv = 'apple,banana,cherry';
$fruits = explode(',', $csv); // ['apple', 'banana', 'cherry']
echo implode(' | ', $fruits); // "apple | banana | cherry"

if (str_contains($text, 'World')) {
echo 'Found World!';
}

$name = 'Alice';
$age = 30;
echo sprintf('Name: %s, Age: %d', $name, $age); // "Name: Alice, Age: 30"

Common sprintf placeholders: %s (string), %d (integer), %f (float), %.2f (float with 2 decimals).

Warning: strpos() returns 0 when the needle is at the start of the string. Since 0 is falsy in PHP, always use strict comparison: if (strpos($haystack, $needle) !== false).

Multibyte strings - a note on Unicode​

strlen() counts bytes, not characters. For ASCII text that is fine. For Unicode (e.g. emoji, accented characters, Chinese), one character can use multiple bytes:

<?php

$emoji = '👋';
echo strlen($emoji); // 4 (bytes) - not 1 character!

For Unicode-aware string handling, use the mbstring extension:

FunctionMultibyte equivalent
strlen()mb_strlen($str, 'UTF-8')
strpos()mb_strpos($haystack, $needle, 0, 'UTF-8')
substr()mb_substr($str, $start, $length, 'UTF-8')
strtolower()mb_strtolower($str, 'UTF-8')
strtoupper()mb_strtoupper($str, 'UTF-8')

Tip: If your application handles user input in multiple languages or emoji, prefer the mb_* functions. The mbstring extension is usually enabled by default in PHP.

Arrays​

An array is an ordered collection of values. You can store numbers, strings, booleans, other arrays, or a mix. Arrays are one of PHP's most powerful features.

What is an array?​

Think of an array as a list or a row of boxes. Each box holds a value, and each box has a position (or a label) so you can access it. Arrays can grow and shrink as you add or remove elements.

Indexed arrays​

An indexed array uses numeric keys starting from 0. You create one with square brackets or the array() function:

<?php

$numbers = [1, 2, 3, 4, 5];
$colors = array('red', 'green', 'blue');

// Both are equivalent. The short syntax [] is preferred in modern PHP.

You access elements by their index (position). Indexing is zero-based - the first element is at index 0:

<?php

$fruits = ['apple', 'banana', 'cherry'];

echo $fruits[0]; // apple
echo $fruits[1]; // banana
echo $fruits[2]; // cherry

Adding and removing elements​

Append to the end with $arr[] = value or array_push():

<?php

$items = ['a', 'b'];
$items[] = 'c'; // ['a', 'b', 'c']
array_push($items, 'd'); // ['a', 'b', 'c', 'd']

Remove from the end with array_pop():

<?php

$stack = [1, 2, 3];
$last = array_pop($stack); // $last is 3, $stack is [1, 2]

Remove from the beginning with array_shift():

<?php

$queue = ['first', 'second', 'third'];
$first = array_shift($queue); // $first is 'first', $queue is ['second', 'third']

Add to the beginning with array_unshift():

<?php

$list = ['b', 'c'];
array_unshift($list, 'a'); // ['a', 'b', 'c']

Remove a specific element with unset():

<?php

$arr = [10, 20, 30];
unset($arr[1]); // Removes index 1; $arr is [10, 30]
// Note: indices are NOT renumbered. $arr[0] is 10, $arr[2] is 30.

Note: unset() removes the key entirely. The array does not automatically reindex. Use array_values() to reindex: $arr = array_values($arr);

Associative arrays​

An associative array uses string (or integer) keys that you choose. Instead of positions, you use meaningful names:

<?php

$user = [
'name' => 'Alice',
'email' => 'alice@example.com',
'age' => 30,
];

echo $user['name']; // Alice
echo $user['email']; // alice@example.com

Use associative arrays when each value has a clear label - user data, configuration, key-value pairs. Use indexed arrays when order matters and you do not need named keys.

Multidimensional arrays​

Arrays can contain other arrays. That gives you multidimensional arrays - arrays of arrays:

<?php

$students = [
['name' => 'Alice', 'grade' => 85],
['name' => 'Bob', 'grade' => 92],
['name' => 'Carol', 'grade' => 78],
];

echo $students[0]['name']; // Alice
echo $students[1]['grade']; // 92

You can nest as deeply as you need. Access nested values by chaining indices: $data['users'][0]['email'].

Looping through arrays​

foreach is the standard way to iterate over arrays. Two forms:

By value only:

<?php

$fruits = ['apple', 'banana', 'cherry'];

foreach ($fruits as $fruit) {
echo $fruit . "\n";
}
// apple
// banana
// cherry

By key and value:

<?php

$scores = ['Alice' => 85, 'Bob' => 92, 'Carol' => 78];

foreach ($scores as $name => $score) {
echo "$name: $score\n";
}
// Alice: 85
// Bob: 92
// Carol: 78

for loop with count() when you need the index:

<?php

$items = ['a', 'b', 'c'];

for ($i = 0; $i < count($items); $i++) {
echo "Index $i: " . $items[$i] . "\n";
}

Tip: Prefer foreach when you do not need the numeric index. It is clearer and avoids off-by-one errors.

Essential array functions​

FunctionDescriptionExample
count($arr)Number of elementscount([1,2,3]) → 3
in_array($needle, $arr)True if value exists in arrayin_array('b', ['a','b','c']) → true
array_key_exists($key, $arr)True if key existsarray_key_exists('x', ['x'=>1]) → true
array_merge($arr1, $arr2)Merge arrays (values appended)array_merge([1,2],[3,4]) → [1,2,3,4]
array_slice($arr, $offset, $len)Extract portion of arrayarray_slice([1,2,3,4], 1, 2) → [2,3]
array_splice($arr, $offset, $len, $replacement)Remove/replace portionModifies array in place
array_map($callback, $arr)Apply function to each elementarray_map('strtoupper', ['a','b']) → ['A','B']
array_filter($arr, $callback)Keep only elements where callback is truthyarray_filter([1,0,2,0,3]) → [1,2,3]
array_reduce($arr, $callback, $initial)Reduce to single valueSum, product, concatenation
sort($arr)Sort by value (reindexes)Modifies in place
asort($arr)Sort by value (keeps keys)Modifies in place
ksort($arr)Sort by keyModifies in place
rsort($arr)Sort by value, descendingModifies in place
array_unique($arr)Remove duplicate valuesReturns new array
array_reverse($arr)Reverse orderReturns new array
array_keys($arr)Get all keysarray_keys(['a'=>1,'b'=>2]) → ['a','b']
array_values($arr)Get all values (reindex)array_values(['x'=>1,'y'=>2]) → [1,2]

Examples:

<?php

$nums = [3, 1, 4, 1, 5];
sort($nums); // [1, 1, 3, 4, 5]
$unique = array_unique($nums); // [1, 3, 4, 5]

$names = ['alice', 'bob', 'carol'];
$upper = array_map('strtoupper', $names); // ['ALICE', 'BOB', 'CAROL']

$scores = [10, 20, 30];
$sum = array_reduce($scores, fn($carry, $n) => $carry + $n, 0); // 60

Destructuring with list() and short syntax​

You can unpack array values into variables in one step:

<?php

$point = [10, 20];
list($x, $y) = $point;
echo "$x, $y"; // 10, 20

// Short syntax (available in all supported PHP 8 versions):
[$x, $y] = $point;

With associative arrays, use the key names:

<?php

$user = ['name' => 'Alice', 'email' => 'alice@example.com'];
['name' => $name, 'email' => $email] = $user;
echo $name; // Alice
echo $email; // alice@example.com

The spread operator in arrays​

The spread operator (...) can merge arrays or insert elements. It is fully available in PHP 8:

<?php

$first = [1, 2, 3];
$second = [4, 5, 6];
$merged = [...$first, ...$second]; // [1, 2, 3, 4, 5, 6]

$middle = ['x', 'y'];
$all = [0, ...$middle, 9]; // [0, 'x', 'y', 9]

This is cleaner than array_merge() when you want to combine arrays or inject elements at specific positions.

Practical example - shopping list and gradebook​

Here is a complete example that uses strings and arrays together. It builds a shopping list, manipulates it, and then processes a simple gradebook:

<?php

// --- Shopping list ---
$shoppingList = ['milk', 'bread', 'eggs'];
$shoppingList[] = 'butter';
$shoppingList[] = 'cheese';

// Remove 'eggs' (find position and unset)
$index = array_search('eggs', $shoppingList);
if ($index !== false) {
unset($shoppingList[$index]);
$shoppingList = array_values($shoppingList);
}

// Build a formatted string
$listStr = implode(', ', $shoppingList);
echo "Shopping list: $listStr\n";

// --- Student gradebook ---
$grades = [
['name' => 'Alice', 'scores' => [85, 90, 88]],
['name' => 'Bob', 'scores' => [78, 82, 80]],
['name' => 'Carol', 'scores' => [92, 95, 90]],
];

foreach ($grades as $student) {
$name = $student['name'];
$scores = $student['scores'];
$average = array_reduce($scores, fn($c, $n) => $c + $n, 0) / count($scores);
$average = round($average, 1);
echo sprintf("%s: %.1f average\n", $name, $average);
}

Output:

Shopping list: milk, bread, butter, cheese
Alice: 87.7 average
Bob: 80.0 average
Carol: 92.3 average

This example uses indexed and associative arrays, foreach, array_search, array_values, implode, array_reduce, count, round, and sprintf - all concepts from this chapter.

Summary​

  • Strings: Use single quotes for literals, double quotes for interpolation. Concatenate with . and .=
  • Heredoc (<<<EOT) interpolates variables; nowdoc (<<<'EOT') does not
  • Essential string functions: strlen, strtolower, strtoupper, trim, str_replace, strpos, substr, explode, implode, str_contains, str_starts_with, str_ends_with, sprintf
  • For Unicode, use mb_strlen, mb_substr, and other mb_* functions
  • Arrays: Indexed arrays use numeric keys (0-based); associative arrays use named keys
  • Add/remove: $arr[] = x, array_push, array_pop, array_shift, array_unshift, unset
  • Loop with foreach ($arr as $value) or foreach ($arr as $key => $value)
  • Essential array functions: count, in_array, array_key_exists, array_merge, array_slice, array_map, array_filter, array_reduce, sort, asort, ksort, array_unique, array_keys, array_values
  • Destructure with [$a, $b] = $arr or ['key' => $var] = $arr
  • Spread operator: [...$arr1, ...$arr2] merges arrays

Next up: Working with Forms & HTTP - HTML forms, GET and POST requests, superglobals, input validation, and building a contact form.