PHP Strings

La Lakshmi Priya Updated 30 Oct 2026
9 min read ·Lesson 208 of 209

What Is a String?

In simple terms: A string is a piece of text — a name, a sentence, an email address, an HTML snippet, or even an entire file's content.

Technically: In PHP, a string is an ordered sequence of bytes. PHP does not store an encoding with the string; it simply stores bytes. When text is saved as UTF-8 (the standard for the web), English letters take one byte each, while characters such as é, ₹, த, or emoji take two to four bytes.

Why Strings Matter

Almost everything a web application handles is text at some point:

  • Form input ($_POST), URL parameters ($_GET), and cookies always arrive as strings
  • HTML output sent to the browser
  • JSON sent to and received from APIs
  • SQL queries, file paths, email bodies, log messages

Understanding how strings are written, stored, and compared prevents a large class of bugs.


Creating Strings

PHP has four ways to write a string literal:

SyntaxNameVariables Interpolated?Escape Sequences?
'text'Single-quotedNoOnly \' and 0
"text"Double-quotedYesYes (\n, \t, \$, …)
<<<ID ... IDHeredocYesYes
<<<'ID' ... IDNowdocNoNo

This lesson focuses on single and double quotes. Heredoc and nowdoc are covered in Heredoc and Nowdoc, escape sequences in Escape Characters, and interpolation in String Interpolation.

Single-Quoted Strings

<?php
$language = 'PHP';

echo 'I am learning $language\n';

Output

I am learning $language\n

Single-quoted strings are literal. $language is not replaced, and \n is printed as a backslash followed by n. The only special sequences are \' (a single quote) and 0 (a backslash).

Double-Quoted Strings

<?php
$language = 'PHP';

echo "I am learning $language\n";

Output

I am learning PHP

Double-quoted strings replace variables with their values and interpret escape sequences such as \n (newline).

Which Quotes Should You Use?

  • Use single quotes for fixed text with no variables: array keys ($user['email']), SQL with placeholders, file paths, regular expression patterns. What you see is exactly what you get.
  • Use double quotes when you need variables or escape sequences inside the text.

The performance difference between the two is negligible in modern PHP. Choose based on clarity.

Quotes Inside Strings

<?php
echo 'It\'s a "great" day' . "\n";
echo "It's a \"great\" day" . "\n";
echo "It's a 'great' day" . "\n";

Output

It's a "great" day
It's a "great" day
It's a 'great' day

A quote of the same type as the delimiter must be escaped with a backslash. A quote of the other type needs no escaping. Choosing the right delimiter often avoids escaping altogether.


Multiline Strings

Strings can span several lines. The line breaks become part of the string.

<?php
$address = "Gocourse Learning Centre
12 Anna Salai
Chennai 600002";

echo $address;

Output

Gocourse Learning Centre
12 Anna Salai
Chennai 600002

In a browser, line breaks inside text are displayed as spaces. To show them as visible line breaks in HTML, use nl2br() (which inserts <br> tags) or wrap the text in a <pre> element.


String Length

strlen() Counts Bytes

<?php
echo strlen("Hello") . "\n";
echo strlen("Hello World") . "\n";
echo strlen("") . "\n";

Output

5
11
0

Spaces count as characters, and an empty string has length 0.

mb_strlen() Counts Characters

<?php
$price = "₹500";
$greeting = "Héllo";

echo strlen($price) . " bytes, " . mb_strlen($price) . " characters\n";
echo strlen($greeting) . " bytes, " . mb_strlen($greeting) . " characters\n";

Output

6 bytes, 4 characters
6 bytes, 5 characters

Why the Results Differ

In UTF-8, ₹ is stored as 3 bytes and é as 2 bytes. strlen() counts every byte; mb_strlen() decodes UTF-8 and counts actual characters.

FunctionCountsUse For
strlen()BytesBinary data, storage limits measured in bytes, ASCII-only identifiers
mb_strlen()CharactersAnything a human reads: names, messages, form validation ("max 50 characters")

For user-facing text, use the mb_* functions. They are covered in Multibyte Strings. Since PHP 8.0, the mbstring functions use UTF-8 by default unless configured otherwise.


Accessing Individual Characters

Strings can be accessed like arrays of bytes using square brackets and a zero-based position (offset).

Example

<?php
$word = "Developer";

echo $word[0] . "\n";    // first character
echo $word[4] . "\n";    // fifth character
echo $word[-1] . "\n";   // last character
echo $word[-3] . "\n";   // third from the end

Output

D
l
r
p

How It Works

  • Offsets start at 0, so $word[0] is D and $word[4] is l (D-e-v-e-l).
  • Negative offsets (PHP 7.1+) count from the end: -1 is the last character.

Reading Beyond the End

<?php
$code = "ABC";
echo $code[10];

This raises a warning ("Uninitialized string offset") and returns an empty string. Check the length first, or use substr(), which handles out-of-range positions without warnings.

Modifying Individual Characters

<?php
$status = "cat";
$status[0] = "b";

echo $status;

Output

bat

PHP strings are mutable at the byte level: you can replace a single byte by assigning to its offset. If you assign beyond the end, PHP pads the gap with spaces.

Warning: Offsets work on bytes, not characters. "₹500"[0] returns only the first of the three bytes of ₹, which is not a valid character on its own. For multibyte text, use mb_substr($text, 0, 1).

Version note: The old syntax $word{0} was removed in PHP 8.0. Always use square brackets.


Strings Are Copied, Functions Return New Strings

String functions do not change the original variable. They return a new string.

<?php
$name = "  priya  ";

trim($name);
echo "[$name]\n";

$name = trim($name);
echo "[$name]\n";

Output

[  priya  ]
[priya]

The first trim() call returns a trimmed string, but the result is discarded because it is not assigned. To keep the change, assign the result back to a variable. This applies to almost all string functions: strtoupper(), str_replace(), substr(), and so on.


Comparing Strings

Equality

<?php
var_dump("apple" === "apple");   // bool(true)
var_dump("Apple" === "apple");   // bool(false) — case-sensitive
var_dump(strcasecmp("Apple", "apple") === 0); // bool(true) — case-insensitive

=== compares strings byte by byte, so uppercase and lowercase letters are different. strcasecmp() compares without case sensitivity and returns 0 when the strings are equal.

Numeric Strings and Loose Comparison

When both sides of == are numeric strings, PHP compares them as numbers:

<?php
var_dump("10" == "1e1");    // bool(true)  — both are the number 10
var_dump("100" == "1e2");   // bool(true)
var_dump("007" == "7");     // bool(true)
var_dump("007" === "7");    // bool(false)

This can cause real bugs — for example, comparing tokens, codes, or hashes that happen to look numeric. Always compare strings with ===.

PHP 8 Change: Comparing Strings With Numbers

<?php
var_dump(0 == "abc");   // bool(false) in PHP 8; bool(true) in PHP 7
var_dump(0 == "");      // bool(false) in PHP 8; bool(true) in PHP 7
var_dump(42 == "42");   // bool(true) in both

In PHP 7, a non-numeric string was converted to a number (0) before comparison, so 0 == "abc" was true. Since PHP 8.0, when a number is compared with a non-numeric string, the number is converted to a string instead, and the comparison is false. This change removed a long-standing source of security bugs.

Ordering Strings

<?php
var_dump(strcmp("apple", "banana"));  // negative: "apple" comes first
var_dump("apple" < "banana");         // bool(true)

$files = ["img12.png", "img10.png", "img2.png"];
sort($files);
print_r($files);

natsort($files);
print_r(array_values($files));

Output

int(-1)
bool(true)
Array
(
    [0] => img10.png
    [1] => img12.png
    [2] => img2.png
)
Array
(
    [0] => img2.png
    [1] => img10.png
    [2] => img12.png
)
  • strcmp() returns a negative number, 0, or a positive number depending on order. Since PHP 8.2, it returns exactly -1, 0, or 1.
  • Standard sorting compares character by character, so "img10" comes before "img2" (because 1 < 2).
  • natsort() uses natural order, which treats numbers inside strings as numbers — the order a human expects.

Converting Between Strings and Numbers

Strings to Numbers

<?php
var_dump((int) "42");        // int(42)
var_dump((float) "3.75");    // float(3.75)
var_dump((int) "12 apples"); // int(12) — leading number is used
var_dump((int) "apples 12"); // int(0)  — no leading number
var_dump("5" + "10");        // int(15)

A string that starts with a number followed by other text ("12 apples") is called a leading-numeric string; casting it with (int) silently uses the leading number. Using such a string directly in arithmetic ("12 apples" + 1) also uses the leading number but raises the warning "A non-numeric value encountered". A completely non-numeric string in arithmetic ("apples" + 1) throws a TypeError in PHP 8. Conversion rules are covered in PHP Casting and PHP Type Juggling.

Validating Numeric Strings

<?php
var_dump(is_numeric("42"));     // bool(true)
var_dump(is_numeric("4.2e1"));  // bool(true)
var_dump(is_numeric(" 42"));    // bool(true)  — leading whitespace allowed
var_dump(is_numeric("42 "));    // bool(true)  — trailing whitespace allowed since PHP 8.0
var_dump(is_numeric("42abc"));  // bool(false)

Numbers to Strings

<?php
$quantity = 3;
$text = "Items: " . $quantity;       // automatic conversion
$formatted = number_format(1234567.891, 2);

var_dump($text, $formatted);

Output

string(8) "Items: 3"
string(12) "1,234,567.89"

Practical Example: Validating and Normalizing a Username

<?php
function normalizeUsername(string $input): ?string
{
    $username = strtolower(trim($input));
    $length = mb_strlen($username);

    if ($length < 3 || $length > 20) {
        return null;
    }

    if (!ctype_alnum(str_replace('_', '', $username))) {
        return null;
    }

    return $username;
}

$inputs = ["  Kavin_R  ", "ab", "hello world", "Dev_2026"];

foreach ($inputs as $input) {
    $result = normalizeUsername($input);
    printf("%-16s => %s\n", "'$input'", $result ?? 'invalid');
}

Output

'  Kavin_R  '    => kavin_r
'ab'             => invalid
'hello world'    => invalid
'Dev_2026'       => dev_2026

Step-by-Step Explanation

  1. trim() removes surrounding spaces, which users often type accidentally.
  2. strtolower() normalizes case so that Kavin_R and kavin_r cannot be registered as two different users.
  3. mb_strlen() counts characters for the length rule.
  4. str_replace('_', '', $username) temporarily removes underscores, then ctype_alnum() checks that every remaining character is a letter or digit. This rejects spaces and symbols while allowing underscores.
  5. The function returns the cleaned username, or null when the input is invalid.

This pattern — trim, normalize, validate, then use — applies to emails, phone numbers, coupon codes, and most other text input.


Common Mistakes

Expecting Variables to Work in Single Quotes

Effect: 'Hello $name' prints $name literally.

Fix: Use double quotes or concatenation.

Using strlen() for User-Facing Length Limits

Effect: A 10-character name in Tamil or with accents may be rejected as "too long".

Fix: Use mb_strlen().

Forgetting to Assign Function Results

Effect: trim($name); has no effect on $name.

Fix: $name = trim($name);

Comparing Strings With ==

Effect: "1e3" == "1000" is true.

Fix: Use === for string comparisons.

Accessing Multibyte Characters by Offset

Effect: Broken characters (often displayed as �).

Fix: Use mb_substr() and other mb_* functions.

Using $str{0}

Effect: Parse error in PHP 8.

Fix: Use $str[0].


Best Practices

  • Use single quotes for literal text and double quotes when interpolating.
  • Store and output all text as UTF-8, and declare <meta charset="UTF-8"> in HTML.
  • Use mb_* functions for anything a human reads.
  • Compare strings with ===; use strcasecmp() for case-insensitive comparison.
  • Remember that string functions return new strings — assign the result.
  • Trim and normalize user input before validating or storing it.

Official reference: https://www.php.net/manual/en/language.types.string.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings Function Arguments PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer PHP Form Handling PHP XML Parsers PDO Transactions PDO Error Handling PHP XML Parsers PHP SimpleXML Parser PHP SimpleXML - Get PHP XML Expat Parser PHP DOM Parser PHP XMLReader PHP XMLWriter AJAX Intro PHP Class Constants Encryption with Sodium Recursive Functions Variable Functions Anonymous Functions Closures Arrow Functions First-class Callable Syntax PHP Arrays Indexed Arrays Associative Arrays Create Arrays Variables Scope Static Variables Variable Variables PHP Echo / Print PHP printf / sprintf PHP Data Types PHP Booleans PHP NULL PHP Strings String Functions
Ask about this post
AI Ask about this post

Ask questions about PHP Strings and get answers drawn from it.

Signed-in readers only.