PHP RFC: Arbitrary string interpolation
- Date: 2022-03-17
- Author: Ilija Tovilo, tovilo.ilija@gmail.com
- Status: Withdrawn
- Target Version: PHP 8.2
- Implementation: https://github.com/php/php-src/pull/8256
Proposal
PHP has four types of string interpolation. The two most common forms are “$foo”
and “{$foo}”
. For details on the two other forms of string interpolation see the deprecate ${} string interpolation RFC.
All the current forms of string interpolation are limited to variables or variable chains (array access, properties, method calls, etc). This probably covers 80% of use cases for string interpolation (unverified figure). However, there are times when this is not enough, namely you might want to embed any of the following in your string:
- Function calls
- Constants
- Class constants
- Static method calls
$world = 'world'; echo "Hello {strtoupper($world)}!"; // Hello {strtoupper(world)} // :(
This RFC proposes to add a new form for string interpolation that works for arbitrary expressions.
$world = 'world'; echo "Hello {$:strtoupper($world)}!"; // Hello WORLD! // :) echo "{$:T_PAAMAYIM_NEKUDOTAYIM}"; echo "{$:Foo::class}"; echo "{$:self::doSomething()}";
The proposed syntax works in all cases where existing string interpolation is allowed, namely double quoted strings (“”
), heredoc (<<<TXT TXT
) and the execution operator (``
).
Motivation
Of course, this can already be achieved in two other ways:
- By creating a temporary local variable
- By stopping the string and concatenating the value with
.
Creating local variables is not a terrible option. It does pollute the variable symbol table a bit and it requires more visual jumping to see what value is being embedded.
Concatenation is a fair bit worse. The quotes and .
symbols lead to a symbol soup, and the approach will not work nicely with heredoc at all.
echo <<<TXT Hello TXT /* <-- Must be on a new line */ . strtoupper('world') . <<<TXT TXT;
Syntax choice
The primary advantage of the syntax “{$:expr}”
is that is it is fully backwards compatible as it leads to a syntax error in PHP 8.1 rather than being interpreted literally. It also looks familiar while being distinctly different from other forms of string interpolation to avoid confusion. The :
could be swapped with another character or even white space, but I believe that white space has a bigger chance of leading to confusion.
A different syntax could be chosen with a given BC break.
echo "Hello #{strtoupper('world')}";
This could be mitigated by adding a prefix to the string itself.
echo $"Hello #{strtoupper('world')}";
I think this is unfortunate because:
- Converting an existing string to
$
will potentially alter its behavior and require escaping of other parts of the string (similar to switching from' to
“
) - The prefix will need to work for all existing string types that allow interpolation (
”
, heredoc, execute operator), doubling the types of interpolated string we have
Escaping
Escaping works by adding a backslash \
after the brace {
.
echo "{\$:foo}"; // {$:foo}
If you're thinking why not before the {
, PHPs existing escaping of \{$foo}
could be considered buggy. While it escapes the {}
, it also gets printed itself.
$foo = 'bar'; echo "\{$foo}"; // \{bar}
That said, escaping the proposed string interpolation {$:
should be very rare in practice.
Backwards incompatible changes
None
Comparison to other languages
Most modern languages have string interpolation that allow arbitrary expressions.
Language | Syntax |
---|---|
C# | $“x + y = {x + y}” |
Dart | 'x + y = ${x + y} ' |
JavaScript | `x + y = ${x + y}` |
Kotlin | “x + y = ${x + y}” |
Python | f'x + y = {x + y} ' |
Raku (Perl6) | “\$x + \$y = { $x + $y }” |
Ruby | “x + y = #{x + y}” |
Scala | s“x + y = ${$x + $y}” |
Swift | “x + y = \(x + y)” |
Credits
Credits to Rowan Tommins (IMSoP) for the syntax suggestion and comparison to other languges.
Vote
Voting starts 2022-xx-x and ends 2022-xx-xx.
As this is a language change, a 2/3 majority is required.