String Functions

PHP has a huge library of string functions — searching, extracting, replacing, splitting, trimming, padding, changing case. They're plain functions rather than methods, and they never change the original string: each returns a new value. This lesson tours the ones you'll use every day.

Case and trimming

PHP
<?php

$input = "   Hello, World!   ";

echo "[", trim($input), "]\n";
echo "[", ltrim($input), "]\n";
echo "[", rtrim($input), "]\n";
echo strtoupper(trim($input)), "\n";
echo strtolower(trim($input)), "\n";
echo ucfirst("hello world"), "\n";
echo ucwords("hello wide world"), "\n";
echo trim("--==Title==--", "-="), "\n";
Output
[Hello, World!]
[Hello, World!   ]
[   Hello, World!]
HELLO, WORLD!
hello, world!
Hello world
Hello Wide World
Title

Trimming input is a good habit: form fields often arrive with stray spaces. The second argument to the trim functions lists the characters to remove.

Searching

PHP
<?php

$text = "The rain in Spain stays mainly in the plain";

var_dump(str_contains($text, "Spain"));
var_dump(str_starts_with($text, "The"));
var_dump(str_ends_with($text, "plain"));
var_dump(strpos($text, "ain"));
var_dump(strrpos($text, "ain"));
var_dump(stripos($text, "SPAIN"));      // case-insensitive
var_dump(strpos($text, "snow"));
echo substr_count($text, "ain"), "\n";
Output
bool(true)
bool(true)
bool(true)
int(5)
int(40)
int(12)
bool(false)
4

strpos returns the position of the first match, or false if there isn't one. That leads to a famous bug: a match at position 0 is falsy too, so always compare with === false or !== false. For a yes/no question, str_contains is clearer anyway.

PHP
<?php

$s = "apple pie";

if (strpos($s, "apple")) {
    echo "found (loose check)\n";
} else {
    echo "not found?! (bug: position 0 is falsy)\n";
}

if (strpos($s, "apple") !== false) {
    echo "found (strict check)\n";
}
Output
not found?! (bug: position 0 is falsy)
found (strict check)

Extracting parts

substr($string, $start, $length) returns part of a string. A negative start counts from the end. strstr returns the part from a match onwards (or before it):

PHP
<?php

$email = "maria.lopez@example.com";
$at = strpos($email, "@");

echo substr($email, 0, $at), "\n";
echo substr($email, $at + 1), "\n";
echo substr($email, -3), "\n";
echo strstr($email, "@"), "\n";
echo strstr($email, "@", true), "\n";
echo strrchr("archive.tar.gz", "."), "\n";   // from the last dot
Output
maria.lopez
example.com
com
@example.com
maria.lopez
.gz

Replacing

PHP
<?php

$s = "I like cats. Cats are great.";

echo str_replace("cats", "dogs", $s), "\n";
echo str_ireplace("cats", "dogs", $s), "\n";
echo str_replace(["I", "great"], ["We", "the best"], $s), "\n";
echo substr_replace("2026-10-08", "**", 5, 2), "\n";
echo strtr("Hi NAME, your code is CODE", ["NAME" => "Ana", "CODE" => "X7"]), "\n";
Output
I like dogs. Cats are great.
I like dogs. dogs are great.
We like cats. Cats are the best.
2026-**-08
Hi Ana, your code is X7

strtr with an array replaces all placeholders in one pass, which makes it handy for simple templates.

Splitting and joining

explode splits a string into an array at a separator; implode joins an array back into a string. str_split splits into fixed-size chunks:

PHP
<?php

$csv = "Oslo,Bergen,Trondheim";
$cities = explode(",", $csv);
echo count($cities), " cities, second is $cities[1]\n";
echo implode(" | ", $cities), "\n";

[$key, $value] = explode("=", "timeout=30=seconds", 2);   // at most 2 parts
echo "$key -> $value\n";

print_r(str_split("ABCDEFGH", 3));
echo ucwords(implode(" ", explode("-", "my-blog-post"))), "\n";
Output
3 cities, second is Bergen
Oslo | Bergen | Trondheim
timeout -> 30=seconds
Array
(
    [0] => ABC
    [1] => DEF
    [2] => GH
)
My Blog Post

Padding and repeating

PHP
<?php

$items = ["Tea" => 2.5, "Coffee" => 3.2, "Hot chocolate" => 3.95];

foreach ($items as $name => $price) {
    echo str_pad($name, 15, "."), str_pad(number_format($price, 2), 6, " ", STR_PAD_LEFT), "\n";
}
echo str_pad("42", 6, "0", STR_PAD_LEFT), "\n";
echo str_repeat("=-", 10), "\n";
Output
Tea............  2.50
Coffee.........  3.20
Hot chocolate..  3.95
000042
=-=-=-=-=-=-=-=-=-=-

Other useful functions

PHP
<?php

echo strrev("stressed"), "\n";
echo wordwrap("The quick brown fox jumps over the lazy dog", 15, "\n", true), "\n";
echo nl2br("line one\nline two"), "\n";
echo number_format(1234.5, 1), "\n";
echo str_word_count("How many words are here?"), "\n";
echo similar_text("World", "Word"), "\n";
echo levenshtein("kitten", "sitting"), "\n";
Output
desserts
The quick brown
fox jumps over
the lazy dog
line one<br />
line two
1,234.5
5
4
3

levenshtein counts the edits needed to turn one string into another — useful for "did you mean…?" suggestions.

Quick reference

TaskFunction
Lengthstrlen (bytes), mb_strlen (characters)
Contains / starts / endsstr_contains, str_starts_with, str_ends_with
Positionstrpos, stripos, strrpos (returns false if missing)
Part of a stringsubstr, strstr, strrchr
Replacestr_replace, str_ireplace, strtr, substr_replace
Split / joinexplode, implode, str_split
Clean uptrim, ltrim, rtrim
Casestrtolower, strtoupper, ucfirst, ucwords
Layoutstr_pad, str_repeat, wordwrap

Try it yourself

Turn a blog post title into a URL "slug": lower-case, with words joined by hyphens and punctuation removed.

Try it yourself · main.php
Edit the code, copy it into main.php, then run it with php main.php (PHP 8.5). How to install PHP
Output
hello-world-php-strings-explained