closure icon indicating copy to clipboard operation
closure copied to clipboard

Syntax error with array access in string interpolation

Open mpesari opened this issue 5 years ago • 11 comments

I have only used this library through another library, but here's a reproducible code:

$ composer require opis/closure
<?php

require_once __DIR__ . '/vendor/autoload.php';

use Opis\Closure\SerializableClosure;

$object = new SerializableClosure(function (): string {
    $a = new \ArrayObject(['foo' => 'bar']);

    return "$a[foo]";
});

$function = unserialize(serialize($object));

var_dump($function());

Result (version 3.5.5):

PHP Parse error:  syntax error, unexpected '' (T_ENCAPSED_AND_WHITESPACE), expecting '-' or identifier (T_STRING) or variable (T_VARIABLE) or number (T_NUM_STRING) in closure://function (): string {
    $a = new \ArrayObject(['foo' => 'bar']);

    return "$a[\foo]";
} on line 5

Result (commit https://github.com/opis/closure/commit/82cc21fefe5f4a56c7c29233129959cb005eb205):

string(3) "bar"

I think the problematic commit is https://github.com/opis/closure/commit/c17ece00ae2f48bbf640482ed699120af330a31c

Of course a workaround is to "fix" all interpolations like this with

return "{$a['foo']}";

mpesari avatar Jun 23 '20 12:06 mpesari

You actually need to always put those single quotes in. The other code you have will generate a warning saying constant 'foo' undefined, treated as string, in PHP 5 and 7, and in PHP 8 will be a hard error.

GrahamCampbell avatar Jun 23 '20 12:06 GrahamCampbell

So, this is actually not a bug, and it is doing the correct thing, to escape the constant to the global namespace with a slash.

GrahamCampbell avatar Jun 23 '20 12:06 GrahamCampbell

AFAIK string interpolation has different rules, e.g. theres two are different:

$a = ['foo' => 'bar'];

print $a[foo]; // references a  nonexistant constant, emits a warning
print "$a[foo]"; // "knows" the context, this does not emit a warning

See https://www.php.net/manual/en/language.types.string.php Example 10 which uses this syntax.

I tried it with a PHP 8 Docker image too:

$ docker run --rm -it keinos/php8-jit
Interactive shell

php > print phpversion();
8.0.0-dev
php > $a = ['foo' => 'bar'];
php > print "$a[foo]";
bar
php > print $a[foo];

Warning: Uncaught Error: Undefined constant 'foo' in php shell code:1
Stack trace:
#0 {main}
  thrown in php shell code on line 1

mpesari avatar Jun 23 '20 12:06 mpesari

Ah, yes. You are right! Hmmm. There is a bug here then. :+1:

GrahamCampbell avatar Jun 23 '20 13:06 GrahamCampbell

Hello there, I have experienced troubles with string interpolations too, but that does not only occur with arrays. I created a repo with some tests :

https://github.com/n00dl3/opis-closure-tests

I also tried with @abdrzakoxa PR (branch abdrzakoxa-pr on the test repo), but it only fixes simple array syntax.

Maybe I should open a new issue ?

n00dl3 avatar Apr 09 '21 11:04 n00dl3

Yes, please open a new issue. Meanwhile I'll check to see where the problem is.

It would have been very helpful to put those tests directly inside opis/closure :)

sorinsarca avatar Apr 09 '21 11:04 sorinsarca

Ok, I've found the problem, a fix is coming in the next minutes.

sorinsarca avatar Apr 09 '21 11:04 sorinsarca

It would have been very helpful to put those tests directly inside opis/closure :)

Yeah, sorry, I started with a single test case and it grew up very quickly...

n00dl3 avatar Apr 09 '21 11:04 n00dl3

String interpolation error was solved in https://github.com/opis/closure/commit/85fec0b113e163c343c9d643744bc1221641f0b9 A new version will be released soon.

This issue (with array access) is not solved yet.

sorinsarca avatar Apr 09 '21 12:04 sorinsarca

Hello @sorinsarca How about my PR, it solves this issue!

abdrzakoxa avatar Apr 09 '21 12:04 abdrzakoxa

@abdrzakoxa I'm looking at that PR right now.

sorinsarca avatar Apr 09 '21 12:04 sorinsarca