Strings that do work
Single and double quotes and what each does with $, interpolation, and the handful of string functions that turn raw text into something presentable.
Two kinds of quotes, two behaviours
A single-quoted string is literal: 'Hello $name' prints exactly that, dollar sign and all. A double-quoted string interpolates: "Hello $name" puts the value in. The difference is the feature, not a quirk to memorise — choose single quotes for text that is just text, and double quotes when a value belongs inside.
Interpolation has one subtlety worth knowing: "Total: $totalItems" looks for the variable $totalItems, not $total. When a variable is followed by letters it should not swallow, wrap it in braces: "Total: {$total} items". The braces are the disambiguator, nothing more.
Functions for the everyday jobs
Text arrives messy — with spaces around it, in the wrong case, with a word that needs replacing. PHP ships the tools for all of it: trim() removes whitespace from both ends, strtoupper() and strtolower() change case, str_replace() swaps one piece of text for another, and strlen() counts characters.
sprintf() is the one to learn early: it builds a string from a template and formats the pieces as it goes — sprintf("%s scored %.1f%%", $name, $score) decides how many decimal places go on the number. It is the difference between dumping a value and presenting it.
Two more functions earn their place in output code: str_pad() makes a value a fixed width by adding spaces or a character, which is how a plain-text table lines up, and str_repeat() builds a separator of exactly the right length. Neither changes the value’s meaning; they change how much room it takes on the line.
Building a string in steps
Most string work is a pipeline, not a single call. A title becomes a slug by trimming it, lowercasing it, removing punctuation, then replacing spaces — four steps, each one a function that returns a new string. The assignment after each step is what carries the result forward: $slug = strtolower($slug); and so on, because the function does not edit in place.
Writing the steps separately is not slower in any way that matters, and it is much easier to check. When the output is wrong, you can print the value after each step and see exactly which one changed it. A single nested expression — str_replace(" ", "-", strtolower(trim($title))) — is the same work with the intermediate values hidden, which is fine once the pipeline is known and painful while it is being built.
Asking questions about text
str_contains("The quick brown fox", "brown") answers whether a piece of text appears, and modern PHP also has str_starts_with and str_ends_with. Before these existed, everyone reached for strpos and its awkward === false dance; the named functions say what they mean.
Strings in PHP are byte sequences, and every string function returns a new string rather than editing the one it was given — $text = trim($text); is the pattern, because trim($text) alone throws its work away. That immutability is the same idea you will meet again with arrays and objects.
Cleaning up a line of text
<?php
$title = ' php strings ';
echo strtoupper(trim($title)) . PHP_EOL; // PHP STRINGS
echo 'Length: ' . strlen(trim($title)) . PHP_EOL; // 11
$text = 'The quick brown fox';
echo str_replace('quick', 'slow', $text) . PHP_EOL;
echo str_contains($text, 'brown') ? 'yes' : 'no' . PHP_EOL;
// sprintf builds a string and formats the pieces.
$name = 'Ada';
$score = 91.5;
echo sprintf('%s scored %.1f%%', $name, $score) . PHP_EOL;
// A returned string must be kept to be useful.
$text = trim(' kept ');
echo '[' . $text . ']' . PHP_EOL;A name badge maker
Run it and compare the raw and the cleaned name. Then add a middle initial to the name, print the badge in lower case as a control line, and make sprintf show the score with no decimal places.
When a line of interpolation turns into punctuation soup, that is the moment to reach for sprintf — it keeps the template in one piece with the values in a row after it.
Bytes, not characters
A PHP string is a sequence of bytes. strlen() counts those bytes, which is the same as the number of characters for plain ASCII and not the same for accented letters or emoji: é is two bytes in UTF-8. That is not a bug to work around with a different loop; it is a reminder that the string type stores bytes and leaves character semantics to functions that know the encoding.
The everyday functions return a new string and leave the original alone. trim($text) hands back a copy with the edges removed; $text = trim($text) is the assignment that keeps it. sprintf() follows the same rule — it builds a new string from a template, with %s for text, %d for a whole number and %% for a literal percent sign. The template stays readable while the values sit in a row after it.
Three string mistakes cost the most time: calling trim($text); and expecting $text to change, comparing strpos() with == false when a match at position 0 is falsy, and using strlen() as a character count on UTF-8 text. Assign the returned string, compare strpos() with === false, and treat the byte count honestly.
Try these next
- Clean a padded name and print it between brackets so the removed spaces are visible.
- Turn a title into a slug: trim it, lower-case it, remove punctuation, then replace spaces with hyphens.
- Format a score with
sprintf()to one decimal place and a literal percent sign.
A title becomes a slug
Run it, then add a subtitle to the title and rebuild the slug. Remove the colon with one call and the spaces with another, so each step stays visible.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What does 'Total: $count' print?
