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
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
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
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
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
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]