Interpolation using ${} syntax with spaces inside the braces

php.internals

Sara Golemon

10 years ago
I'm trying to decide just whether or not https://bugs.php.net/bug.php?id=71927 is "working as intended" as well as what the expected behavior in this situation /should/ be. https://3v4l.org/HfU1g indicates that at the very least HHVM and PHP disagree on the correct output, and testing the same sort of expression in bash says that it's not having any of it; "invalid substitution" warnings abound. The PHP behavior is just kinda weird. "${ great}" does constant interpolation yielding "$my" which in turn becomes variable interpolation and we find up with "my value". I'm actually doubtful that PHP pulls off this juggling *by accident*, which is why I'm posting about it before even going to the extent of proposing an RFC. Does anyone have historical context on this and can explain the current behavior as "working as intended"? -Sara

Davey

10 years ago
Whitespace inside of { } should not matter, the contents should be evaluated as an expression and it's results used to determine the variable name, so ${great} should also be $my as in the other cases. Is this related to the use of quotes around string array keys inside strings? e.g. "$foo[great]" does not evaluate to $foo['my'] but to $foo['great']. - Davey On Tue, Apr 12, 2016 at 8:08 PM, Sara Golemon <pollita@php.net> wrote:

Sara Golemon

10 years ago
On Thu, Apr 14, 2016 at 3:37 AM, Davey Shafik <davey@php.net> wrote:
> Whitespace inside of { } should not matter, the contents should be evaluated > as an expression and it's results used to determine the variable name, so > ${great} should also be $my as in the other cases. >
Right. Which is why I'm conflicted on bug/not-bug/different-bug. IMO, the label inside ${...} should either always be a variable name (like HHVM handles it), or always be an expression. What we have is "It's always an expression except in the one specific case of it being a valid variable name, in which case that takes precedence. Since the versions containing spaces aren't valid variable names, they fall back on the more general expression handling. So I'd be inclined to say "That exception to the rule is the problem", except that this is variable interpolation behavior that goes ALL THE WAY BACK, and I wouldn't break BC for the world. So the question becomes: What's the right move going forward. My inclination would be to either: A: Ignore surrounding whitespace within the ${...} expression. Essentially, adopt HHVM's output for these examples. B: Throw an error on surrounding whitespace. This will make discovering timebombs like these in existing code easier to catch. In either case, if the programmer actually did want the constant->variable double-interpolation, that could be easily achieved via "${(foo)}" which disambiguated foo as a variable name from foo as an expression. -Sara
> Is this related to the use of quotes around string array keys inside > strings? > > e.g. "$foo[great]" does not evaluate to $foo['my'] but to $foo['great']. >
I don't think so... I have a feeling that's yet another weird oddity to PHP parsing that's waiting to bite us in new and surprising ways. -Sara

Simon J Welsh

10 years ago
> On 15/04/2016, at 9:40 AM, Sara Golemon <pollita@php.net> wrote: > > On Thu, Apr 14, 2016 at 3:37 AM, Davey Shafik <davey@php.net> wrote: >> Whitespace inside of { } should not matter, the contents should be evaluated >> as an expression and it's results used to determine the variable name, so >> ${great} should also be $my as in the other cases. >> > Right. Which is why I'm conflicted on bug/not-bug/different-bug. > > IMO, the label inside ${...} should either always be a variable name > (like HHVM handles it), or always be an expression. What we have is > "It's always an expression except in the one specific case of it being > a valid variable name, in which case that takes precedence. Since the > versions containing spaces aren't valid variable names, they fall back > on the more general expression handling. > > So I'd be inclined to say "That exception to the rule is the problem", > except that this is variable interpolation behavior that goes ALL THE > WAY BACK, and I wouldn't break BC for the world. > > So the question becomes: What's the right move going forward. My > inclination would be to either: > A: Ignore surrounding whitespace within the ${...} expression. > Essentially, adopt HHVM's output for these examples. > B: Throw an error on surrounding whitespace. This will make > discovering timebombs like these in existing code easier to catch. > > In either case, if the programmer actually did want the > constant->variable double-interpolation, that could be easily achieved > via "${(foo)}" which disambiguated foo as a variable name from foo as > an expression. > > -Sara > >> Is this related to the use of quotes around string array keys inside >> strings? >> >> e.g. "$foo[great]" does not evaluate to $foo['my'] but to $foo['great']. >> > I don't think so... I have a feeling that's yet another weird oddity > to PHP parsing that's waiting to bite us in new and surprising ways. > > -Sara
When not inside a string, the inside of the ${...} is always treated as an expression, by both PHP and HHVM (https://3v4l.org/i2kOP), so that looks like the “correct” handling for inside a string. There is also differing behaviour in PHP when using array access, depending on if the label starts with a space or not (https://3v4l.org/YPXkr). This behaviour is inconsistent with not using array access. HHVM follows the <=PHP5.5 behaviour of not allowing array access on a constant. However, there is the massive BC break if the handling inside a string changes
-- Simon Welsh

Rowan Collins

10 years ago
Simon Welsh wrote on 15/04/2016 00:52:
> When not inside a string, the inside of the ${...} is always treated as an > expression, by both PHP and HHVM (https://3v4l.org/i2kOP), so that looks like the > “correct” handling for inside a string.
The in-quotes behaviour makes sense when you consider the use cases it solves, e.g. $foo = 'percent'; echo "${foo}age"; Arguably, the alternative bracketing style is clearer here, and doesn't have the name-expression conflict: $foo = 'percent'; echo "{$foo}age"; So possibly you're right - in an ideal world ${ ... } should evaluate an expression whether inside a string or out, and {$...} can be used inside a string for isolating variables. But given the horrendous BC issues of changing that now, I'm inclined to say that surrounding whitespace should be an error, and force the user to use less ambiguous syntax. It occurs to me that this problem is made worse by the "implicit constant definition" where an undefined constant becomes a string. Removing the definition of the constant from the example, and suppressing notices, gives identical output in all versions: https://3v4l.org/3i2El Leave the notices on, though, and you'll see they're getting to that answer in different ways - PHP is mapping expression -> undefined constant -> string -> variable name. So you could have code that works one way for years, then define a global constant with the same name as the local variable, and suddenly everything would go haywire. I would love to see that implicit definition officially deprecated, but that's for another thread... Regards,
-- Rowan Collins [IMSoP]