Combining strings and variables in PHP 8+: examples and common mistakes
Combining strings and variables in PHP is one of the first skills every backend developer learns, yet teams still debate concatenation vs interpolation years later. In PHP 8 and PHP 8.3 codebases the core syntax did not change, but stricter typing, template engines and static analysis tools changed how we should write string output. This guide walks through four core methods, adds PHP 8+ examples, maps them to Symfony, Laravel and Drupal, and lists the mistakes that still cause bugs in production.
If you are new to the language, start with why it is good to learn PHP and our overview of PHP 8 features. For deeper runtime context, see how the PHP interpreter works.
In this article:
- What are the main ways to combine strings and variables in PHP?
- How do you combine strings and variables in practice?
- What changed in PHP 8+ for string handling?
- How do Symfony, Laravel and Drupal handle string output?
- What are the most common mistakes when combining strings and variables?
- Which approach should you choose? Practical recommendations
- How do concatenation methods compare for performance?
- Need help modernizing your PHP codebase?
What are the main ways to combine strings and variables in PHP?
PHP gives you four common ways to build dynamic strings: concatenation with single quotes, interpolation inside double quotes, sprintf() formatting and heredoc/nowdoc blocks. Each has different readability, escaping rules and maintenance cost. Picking the wrong one for a use case is a frequent source of hard-to-read code and subtle bugs.
Single quotes with concatenation
A single-quoted string does not expand variables. You must concatenate with the dot operator:
'Variable is ' . $var;Use this when the string is static or when you want zero variable parsing overhead. For anything with more than one variable, concatenation chains become noisy quickly.
Double quotes and in-string variables
Inside double quotes, PHP expands variables and many escape sequences:
"Variable is {$var}";Wrap complex expressions in braces: "Value: {$user['name']}" or "ID: {$object->id}". This is often the fastest readable option for short dynamic strings.
sprintf() and vsprintf()
sprintf() replaces placeholders in a template string. It is slower than direct interpolation but easier to maintain when you repeat placeholders or need number formatting:
sprintf('Variable is %s', $var);Pass an array with vsprintf() or spread syntax in PHP 8+:
$vars = ['PHP', 'Developer', 'time to code'];
$str = sprintf('Knock knock, "%s" has you. Wake up %s, %s', ...$vars);Ordered placeholders such as %1$s let you reuse a value without duplicating arguments.
Heredoc and nowdoc
Heredoc behaves like a double-quoted string across multiple lines. Since PHP 7.3 the closing identifier can be indented, which makes heredoc much cleaner in modern code:
$str = <<<STR
Variable is $var
STR;Nowdoc (opening identifier in single quotes) behaves like single quotes: no variable expansion. Use heredoc for multiline HTML or SQL fragments; use nowdoc for static multiline literals.
How do you combine strings and variables in practice?
Consider this message template:
Knock knock, "LANG" has you. Wake up NAME, ACTIONConcatenation:
$str = 'Knock knock, "' . $lang . '" has you. Wake up ' . $name . ', ' . $action;Interpolation:
$str = "Knock knock, \"{$lang}\" has you. Wake up {$name}, {$action}";sprintf():
$str = sprintf('Knock knock, "%s" has you. Wake up %s, %s', $lang, $name, $action);Heredoc:
$str = <<<STR
Knock knock, "$lang" has you. Wake up $name, $action
STR;For multiline markup, heredoc usually wins on readability:
$html = <<<HTML
<div class="container">
<p style="font-size:{$size}px;line-height:{$size}px;display:{$display}">
<span class="first-item" style="color:red">{$text1}</span>
<span class="last-item" style="color:black">{$text2}</span>
</p>
</div>
HTML;Read also: examples of PHP projects that show what the language can do and improving code quality with PHP CodeSniffer.
What changed in PHP 8+ for string handling?
The basic rules for combining strings and variables in PHP did not change in PHP 8. Concatenation, interpolation, heredoc and sprintf() work the same way. What changed is the environment around the code: typed properties, constructor property promotion, named arguments, enums and stricter static analysis with tools such as PHPStan and Psalm.
A few PHP 8+ patterns affect how you build strings in application code:
- Named arguments make long
sprintf()or translation calls easier to read without reordering positional parameters. - Union and intersection types push teams to cast or format values explicitly instead of relying on implicit string conversion.
- Match expressions often replace nested concatenation when mapping status codes to messages.
- Stringable objects (implementing
Stringable) can appear in string context, but explicit formatting is still safer in user-facing output.
Example with typed properties and explicit formatting in PHP 8.3:
final class OrderLabel
{
public function __construct(
private readonly int $orderId,
private readonly string $customerName,
) {}
public function toLabel(): string
{
return sprintf('Order #%d for %s', $this->orderId, $this->customerName);
}
}For simple output, concatenation is still fine. For readable templates, interpolation or heredoc may be clearer. For formatted messages with repeated placeholders, sprintf() is often easier to maintain. See also the JIT compiler in PHP 8 and PHP version history for broader runtime changes.
How do Symfony, Laravel and Drupal handle string output?
Modern PHP frameworks rarely build HTML in controllers with raw concatenation. They delegate output to templates and translation layers, which is the pattern you should follow in new code.
Symfony
Symfony controllers return responses built from Twig templates. User-visible strings go through the Translation component with placeholders instead of inline concatenation:
$this->translator->trans('order.label', ['%id%' => $orderId, '%name%' => $name]);For CLI or logging messages, sprintf() or heredoc in a dedicated class keeps controllers thin.
Laravel
Laravel uses Blade templates with {{ $variable }} for escaped output and {!! $html !!} only when you intentionally output raw HTML. Translations use __() with named placeholders:
__('messages.welcome', ['name' => $user->name]);Avoid building Blade fragments as concatenated strings in controllers; pass data arrays to views instead.
Drupal
Drupal renders pages with Twig. Modules use t(), formatPlural() and the StringTranslationTrait rather than echoing concatenated HTML in route callbacks. Example:
$this->t('Order #@id for @name', ['@id' => $orderId, '@name' => $name]);Placeholders starting with @ run through escaping; use % only when the value is already safe. For local development setup, see IDE and Linux configuration for PHP and Drupal.
What are the most common mistakes when combining strings and variables?
Even experienced developers hit the same issues when they mix string styles or skip escaping rules:
- Using single quotes and expecting interpolation:
'Hello $name'prints a literal$name, not the variable value. - Mixing HTML output with unescaped user input: concatenating
$_GET['q']or database fields into HTML creates XSS risk. Escape for context (HTML, URL, JS) or use a template engine. - Building SQL with concatenated values: never assemble queries from raw user input. Use prepared statements with bound parameters.
- Creating long unreadable lines: a 200-character concatenation chain is harder to review than heredoc or
sprintf(). - Forgetting braces with arrays and objects:
"$user['name']"is ambiguous; use"{$user['name']}". - Implicit type coercion surprises: in PHP 8+, passing
nullor objects to string context may throw or behave differently than in PHP 7. Format explicitly. - Duplicating translation strings: slightly different concatenated messages in three places break localization workflows. Centralize copy in translation files.
Which approach should you choose? Practical recommendations
Use this decision guide when you search for long-tail answers such as "PHP concatenate string and variable", "PHP heredoc vs double quotes" or "sprintf vs concatenation PHP":
- Short log or exception messages (1–2 variables): double-quoted interpolation or
sprintf(). - Multiline HTML, email bodies or SQL snippets: heredoc with explicit
{$var}braces. - User-facing UI text in frameworks: translation APIs (Symfony Translator, Laravel
__(), Drupalt()), not raw concatenation in controllers. - Repeated placeholders or numeric formatting:
sprintf()with ordered placeholders such as%1$s. - Static multiline config or regex: nowdoc to avoid accidental variable expansion.
- Legacy PHP 7 code on PHP 8.3: prefer explicit casts and typed helpers over implicit string conversion; run PHPStan level 6+ to catch weak assumptions.
Default to the option your team can review fastest in pull requests. In most Symfony, Laravel and Drupal projects that means templates plus translation helpers, with heredoc or sprintf() limited to CLI scripts, emails and small value objects.
How do concatenation methods compare for performance?
The original benchmarks for this article ran on PHP 7.3 with five million iterations. On PHP 8+, micro-differences between single quotes, double quotes and heredoc are negligible in real applications. Profile your own endpoints if string building appears in hot paths; in typical web requests, I/O and database time dominate.
Practical performance notes:
- Simple strings: concatenation and interpolation perform similarly on modern PHP.
- Complex strings with many variables: double quotes and heredoc usually beat long concatenation chains.
- sprintf(): the slowest of the common options, but still fine for logging, CLI output and occasional formatting.
Read also: what is the best PHP IDE and how to select the right tool and PHPStorm shortcuts that help you work faster.
Keep the existing performance chart image from the CMS if it is still attached to this post.
Need help modernizing your PHP codebase?
This article reflects patterns we use daily on Symfony, Laravel and Drupal projects at Droptica, from greenfield APIs to legacy PHP 7 migrations on PHP 8.3. Clean string handling is a small detail, but it reduces XSS risk, simplifies translations and makes static analysis reliable across large codebases.
If your PHP application needs cleanup, framework migration or long-term maintenance, our team handles audits, upgrades and feature work on production systems. Visit our PHP development services page to see how we can help. For broader context on choosing the language, read why it is good to choose PHP — interview with PHP developers from Droptica.