Hello Internals!
At the moment, there is a feature/bug in the PHP that allows to use
interpolation of generators.
$code = <<<EXAMPLE
Hello ${yield}
EXAMPLE;
I suspect that initially this functionality was not thought out, but it
partially works, which allows you to implement useful functionality.
[$query, $params] = sql(fn() => <<<SQL
SELECT * FROM users WHERE id = ${yield 42} OR id = ${yield 0xDEADBEEF}
SQL);
// Expected
// $query = "SELECT * FROM users WHERE id = ? OR id = ?"
// $params = [ 42, 0xDEADBEEF ]
When I say that the functionality was not thought out initially, I mean
the behavior of generators within strings. For example, the following
code, which should (seemingly) implement this functionality:
function sql(\Closure $expr)
{
[$generator, $params] = [$expr(), $params];
while ($generator->valid()) {
$params[] = $generator->current(); // Get the value from "yield"
$generator->send('?'); // Insert placeholder
}
return [$generator->getReturn()];
}
Causes an error:
Warning: Undefined variable $?
That is, the expression "${yield 42}" expects back not the result of
this expression, but the name of the variable. Therefore, a complete and
workable implementation of such a functionality is as follows:
https://gist.github.com/SerafimArts/2e7702620480fbce6c24bc87bfb9cb0e
I think it makes sense to do something about it. I have two suggestions:
-
Forbid using "yield" inside strings
-
Expect not a variable name as a result of this expression, but a
substitution value.
What do you think?
Hello Internals!
At the moment, there is a feature/bug in the PHP that allows to use
interpolation of generators.$code = <<<EXAMPLE Hello ${yield} EXAMPLE;
I suspect that initially this functionality was not thought out, but it
partially works, which allows you to implement useful functionality.[$query, $params] = sql(fn() => <<<SQL SELECT * FROM users WHERE id = ${yield 42} OR id = ${yield 0xDEADBEEF} SQL); // Expected // $query = "SELECT * FROM users WHERE id = ? OR id = ?" // $params = [ 42, 0xDEADBEEF ]
When I say that the functionality was not thought out initially, I mean
the behavior of generators within strings. For example, the following
code, which should (seemingly) implement this functionality:function sql(\Closure $expr) { [$generator, $params] = [$expr(), $params]; while ($generator->valid()) { $params[] = $generator->current(); // Get the value from "yield" $generator->send('?'); // Insert placeholder } return [$generator->getReturn()]; }
Causes an error:
Warning: Undefined variable $?
That is, the expression "${yield 42}" expects back not the result of
this expression, but the name of the variable. Therefore, a complete and
workable implementation of such a functionality is as follows:
https://gist.github.com/SerafimArts/2e7702620480fbce6c24bc87bfb9cb0eI think it makes sense to do something about it. I have two suggestions:
Forbid using "yield" inside strings
Expect not a variable name as a result of this expression, but a
substitution value.
This doesn't really have anything to do with yield. ${expr} is PHP's
general variable-variable syntax, which looks up the variable with name
returned by expr. The syntax also works inside strings in the form of
"${expr}". Using "${yield $v}" is just a specific instance of the general
pattern following the same rules. (This syntax has a special case that
should be deprecated: "${label}" will be interpreted the same as "$label"
instead, which is inconsistent with how it works everywhere else. This is
also why ${yield} without argument will not perform a yield and instead
look for a variable called $yield.)
PHP unfortunately doesn't have a general expression interpolation syntax,
you can only interpolate variables and certain variable-like constructs.
Regards,
Nikita
Yes you are right. The same thing happens if you put a function there.
function hi(): string
{
return ‘World’;
}
echo <<<MSG
Hello ${hi()}
MSG;
// Warning: Undefined variable $World!
For some reason, I did not take this case into account.
Although it seems to me such semantics are old and require removal from the language, I admit that there is code that uses it and changing the behavior will break a lot. Ideally, I would like to see a similar behavior:
echo "Hello ${ $var }"; // Hello World
echo "Hello ${ 'Wo' . 'rld' }"; // same
echo "Foo ${ some_foo(42) }";
echo "Foo ${ 23 + 42 }";
echo "Some ${ ClassName::method() >> 2 ?? $any }";
// etc
Пятница, 8 октября 2021, 12:22 +03:00 от Nikita Popov nikita.ppv@gmail.com:
Hello Internals!
At the moment, there is a feature/bug in the PHP that allows to use
interpolation of generators.$code = <<<EXAMPLE Hello ${yield} EXAMPLE;
I suspect that initially this functionality was not thought out, but it
partially works, which allows you to implement useful functionality.[$query, $params] = sql(fn() => <<<SQL SELECT * FROM users WHERE id = ${yield 42} OR id = ${yield 0xDEADBEEF} SQL); // Expected // $query = "SELECT * FROM users WHERE id = ? OR id = ?" // $params = [ 42, 0xDEADBEEF ]
When I say that the functionality was not thought out initially, I mean
the behavior of generators within strings. For example, the following
code, which should (seemingly) implement this functionality:function sql(\Closure $expr) { [$generator, $params] = [$expr(), $params]; while ($generator->valid()) { $params[] = $generator->current(); // Get the value from "yield" $generator->send('?'); // Insert placeholder } return [$generator->getReturn()]; }
Causes an error:
Warning: Undefined variable $?
That is, the expression "${yield 42}" expects back not the result of
this expression, but the name of the variable. Therefore, a complete and
workable implementation of such a functionality is as follows:
https://gist.github.com/SerafimArts/2e7702620480fbce6c24bc87bfb9cb0eI think it makes sense to do something about it. I have two suggestions:
Forbid using "yield" inside strings
Expect not a variable name as a result of this expression, but a
substitution value.This doesn't really have anything to do with yield. ${expr} is PHP's
general variable-variable syntax, which looks up the variable with name
returned by expr. The syntax also works inside strings in the form of
"${expr}". Using "${yield $v}" is just a specific instance of the general
pattern following the same rules. (This syntax has a special case that
should be deprecated: "${label}" will be interpreted the same as "$label"
instead, which is inconsistent with how it works everywhere else. This is
also why ${yield} without argument will not perform a yield and instead
look for a variable called $yield.)PHP unfortunately doesn't have a general expression interpolation syntax,
you can only interpolate variables and certain variable-like constructs.Regards,
Nikita
--
Kirill Nesmeyanov
Yes you are right. The same thing happens if you put a function there.
function hi(): string { return ‘World’; } echo <<<MSG Hello ${hi()} MSG; // Warning: Undefined variable $World!
For some reason, I did not take this case into account.
Although it seems to me such semantics are old and require removal from the language, I admit that there is code that uses it and changing the behavior will break a lot. Ideally, I would like to see a similar behavior:echo "Hello ${ $var }"; // Hello World echo "Hello ${ 'Wo' . 'rld' }"; // same echo "Foo ${ some_foo(42) }"; echo "Foo ${ 23 + 42 }"; echo "Some ${ ClassName::method() >> 2 ?? $any }"; // etc
See also
https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation.
--
Christoph M. Becker
See also
https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation.
A couple of other relevant threads:
- Adding whitespace inside the braces changes the interpretation (note
that the mentioned behaviour of undefined constants has indeed changed
in PHP 8.0): https://externals.io/message/92239 - A brief thread about adding a more general interpolation syntax:
https://externals.io/message/111519
Regards,
--
Rowan Tommins
[IMSoP]