PHP String Interpolation

String interpolation is PHP’s ability to embed variables and expressions directly inside a string literal so that PHP substitutes their values automatically when the string is built. Instead of stitching text together with the concatenation operator (.), you write the variable right where its value should appear. This makes messages, log lines, HTML fragments, and templated text far easier to read and write, and it is one of the first things every PHP developer relies on daily.

Overview: How String Interpolation Works

Interpolation is a feature of specific string types, not of PHP strings in general. It only happens inside double-quoted strings ("...") and heredoc blocks (<<<EOT ... EOT). It does not happen inside single-quoted strings ('...') or nowdoc blocks (<<<'EOT' ... EOT) — those are always treated as literal text.

When PHP compiles a double-quoted string or heredoc, its lexer scans the text looking for a dollar sign ($) that is not escaped with a backslash. When it finds one, it stops treating that portion as plain text and starts parsing a restricted variable expression: a variable name, optionally followed by a single array index or a single ->property access. Everything else — literal characters, punctuation, spaces — is kept as-is. The result is that a single double-quoted string is really compiled as an ordered list of literal chunks and variable-fetch instructions, which PHP stitches together at runtime, every time that line of code executes.

This matters for two reasons. First, interpolation is resolved with the current value of a variable at the moment the string expression runs — not at compile time and not once-and-for-all. If you change a variable and build the string again, you get the new value. Second, because the lexer uses a small, fixed set of rules to decide what counts as “inside” the variable expression, only simple expressions are supported directly. Anything more complex (a method call, a chained property, a nested array with a computed key) needs the curly-brace “complex syntax”, covered below.

Syntax

There are two interpolation syntaxes, plus heredoc/nowdoc for multi-line text.

Syntax Form Supports
Simple syntax "$name" A plain variable
Simple syntax (array) "$arr[key]" One array index; the key is written without quotes
Simple syntax (property) "$obj->prop" One level of object property access only — no chaining, no method calls
Complex (curly-brace) syntax "{$expr}" Any PHP expression: method calls, chained properties, static access, computed array keys, nested arrays

Key points about the syntax:

  • $ must be immediately followed by a valid variable-name character (a letter or underscore) to be treated as the start of a variable; otherwise it is printed literally.
  • To print a literal dollar sign right before what would otherwise look like a variable, escape it: "Price: \$total".
  • Inside simple-syntax array access, the key is a bare word or number — $arr[key], not $arr['key']. Quoting the key requires the curly-brace form: {$arr['key']}.
  • Heredoc (<<<EOT ... EOT;) interpolates exactly like a double-quoted string, which makes it ideal for multi-line templated text without needing to escape inner double quotes.
  • Nowdoc (<<<'EOT' ... EOT;) behaves like a single-quoted string: nothing is interpolated. It’s useful for literal text full of dollar signs, such as regular expressions or shell snippets.
<?php
$name = "Sam";
$data = ['key' => 'value'];
$obj  = new stdClass();
$obj->prop = "hi";

// Simple syntax
echo "Hello $name";
echo "Value: $data[key]";
echo "Prop: $obj->prop";

// Complex (curly-brace) syntax
echo "Hello {$name}";
echo "Value: {$data['key']}";
echo "Prop: {$obj->prop}";

Examples

Example 1: Basic variable interpolation

<?php
$name = "Alice";
$age = 29;

echo "Hello, $name! You are $age years old." . PHP_EOL;

Output:

Hello, Alice! You are 29 years old.

PHP scans the double-quoted string, finds $name and $age, and substitutes their current values while leaving every other character untouched. No concatenation operators are needed.

Example 2: Array values and object properties

<?php
class User {
    public string $username = "coder42";
}

$user = new User();
$scores = ['math' => 95, 'science' => 88];

echo "User {$user->username} scored $scores[math] in math." . PHP_EOL;
echo "User {$user->username} scored {$scores['science']} in science." . PHP_EOL;

Output:

User coder42 scored 95 in math.
User coder42 scored 88 in science.

The first line mixes a curly-brace property access with a simple, unquoted array key ($scores[math]). The second line uses curly braces for both, which is required as soon as the array key needs quotes, as with 'science'.

Example 3: Heredoc with method calls and escaped dollar signs

<?php
class Order
{
    public function __construct(
        public string $product,
        public float $price,
        public int $quantity
    ) {}

    public function getTotal(): float
    {
        return $this->price * $this->quantity;
    }
}

$order = new Order('Keyboard', 49.99, 3);

$receipt = <<<TEXT
Order summary
-------------
Product:  {$order->product}
Quantity: {$order->quantity}
Total:    \${$order->getTotal()}
TEXT;

echo $receipt . PHP_EOL;

Output:

Order summary
-------------
Product:  Keyboard
Quantity: 3
Total:    $149.97

This heredoc block interpolates promoted constructor properties and even calls a method, getTotal(), because it is wrapped in curly braces. The \$ before the brace prints a literal dollar sign rather than starting a variable, so the total reads as currency.

Under the Hood

When the Zend engine compiles a double-quoted string or heredoc that contains a $, it does not treat the string as one opaque literal. Its lexer breaks the content into a sequence of tokens: chunks of literal text (T_ENCAPSED_AND_WHITESPACE), variable tokens (T_VARIABLE), and, when curly braces are used, a marker that hands control to the full expression parser for whatever is inside { }. The compiler assembles these pieces into an internal “encapsulated string” node that records the exact order of literal text and variable/expression fetches.

At compile time, PHP turns that node into bytecode. For two or more interpolated pieces, it typically emits a small chain of rope opcodes (ZEND_ROPE_INIT, ZEND_ROPE_ADD, ZEND_ROPE_END) that pre-calculate the total buffer size and copy each fragment into the final string once, which is more efficient than repeatedly reallocating a buffer the way naive chained concatenation could. This is why interpolation and concatenation usually perform similarly in modern PHP — the engine optimizes both — but interpolation keeps the source code visually closer to the final text.

Crucially, only the parsing of which tokens are variables happens at compile time. The actual values are fetched at runtime, every time that line executes, which is why the same interpolated string can print different output on each call if the underlying variables change. Heredoc uses exactly the same encapsulated-string machinery as double-quoted strings; only the delimiters differ, which is why the interpolation rules are identical between the two.

Common Mistakes

Mistake 1: Letters right after the variable name get absorbed into it

PHP’s simple syntax treats any letter, digit, or underscore right after $name as part of the variable name. If you meant to interpolate $name followed by literal text that happens to start with a valid identifier character, PHP will instead look for a longer, different variable.

<?php
$name = "invoice";

echo "Saving file as $name_backup.pdf" . PHP_EOL;

Output:

Saving file as .pdf

PHP looked for a variable called $name_backup, which was never defined, so it interpolated an empty string (and PHP emits an “undefined variable” warning). The fix is to wrap the variable in curly braces so PHP knows exactly where the variable name ends:

<?php
$name = "invoice";

echo "Saving file as {$name}_backup.pdf" . PHP_EOL;

Output:

Saving file as invoice_backup.pdf

Mistake 2: Expecting single-quoted strings to interpolate

Single-quoted strings never interpolate variables — they only support two escape sequences (\\ and \'). A very common beginner mistake is writing a string with variables using single quotes and being surprised the variable name prints literally.

<?php
$user = "Sam";

echo 'Welcome back, $user!' . PHP_EOL;

Output:

Welcome back, $user!

Switching to double quotes fixes it immediately:

<?php
$user = "Sam";

echo "Welcome back, $user!" . PHP_EOL;

Output:

Welcome back, Sam!

Best Practices

  • Use curly-brace complex syntax ({$expr}) for anything beyond a plain variable — method calls, chained properties, static access, or array keys that need quotes.
  • Prefer double-quoted interpolation over string concatenation when mixing a handful of variables into readable text; switch to sprintf() or a template when a string has many placeholders or needs padding/formatting.
  • Use number_format() or sprintf() for currency, percentages, and padded numbers rather than trying to format numbers inline inside an interpolated string.
  • Reach for heredoc when building multi-line templated text (emails, SQL, HTML fragments) so you avoid escaping quotes and chaining . operators.
  • Use nowdoc (or single quotes) for text that is mostly literal dollar signs, such as regular expressions or shell commands, to avoid constant escaping.
  • Always escape interpolated values that end up in HTML output with htmlspecialchars() to prevent XSS, since interpolation itself does no escaping.
  • If an interpolated expression is hard to read at a glance, assign it to a well-named variable first, then interpolate the variable.

Practice Exercises

  • Create an associative array with keys title, author, and price describing a book. Print a single sentence such as “1984 by George Orwell costs $9.99” using simple syntax where possible and curly-brace syntax where required.
  • Write a class Temperature with a property $celsius and a method toFahrenheit() that returns the converted value. Use curly-brace syntax to interpolate the result of calling toFahrenheit() directly inside a sentence.
  • Take three separate echo statements joined with the concatenation operator and rewrite them as a single heredoc block that interpolates the same variables.

Summary

  • Interpolation only works inside double-quoted strings and heredoc blocks — never inside single-quoted strings or nowdoc.
  • Simple syntax handles a plain variable, one array index (unquoted key), or one level of object property access.
  • Complex (curly-brace) syntax, {$expr}, is required for method calls, chained access, quoted array keys, and any expression beyond the simple cases.
  • PHP parses the string into literal chunks and variable-fetch instructions at compile time, but fetches actual values at runtime, every time the string executes.
  • Letters or digits right after a variable name are absorbed into it, which is the most common interpolation bug — curly braces prevent it.
  • Escape a literal dollar sign with a backslash (\$) when it should not start an interpolation.