On Fri, Oct 8, 2021 at 10:55 AM Nesmeyanov Kirill <n...@xakep.ru> wrote:
> 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: > > 1) Forbid using "yield" inside strings > > 2) 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