mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-31 04:27:00 +00:00
Fix array access with a Stringable key on ArrayAccess objects using object keys
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# 3.28.1 (2026-XX-XX)
|
||||
|
||||
* Fix array access with a `Stringable` key coercing the key to string for `ArrayAccess` objects that use object keys (such as `SplObjectStorage`)
|
||||
* Fix duplicated macro argument names triggering a PHP fatal error instead of a `SyntaxError`
|
||||
|
||||
# 3.28.0 (2026-07-03)
|
||||
|
||||
@@ -74,7 +74,7 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest
|
||||
->raw($var)
|
||||
->raw('[')
|
||||
;
|
||||
$this->compileArrayKey($compiler);
|
||||
$this->compileArrayKey($compiler, $var);
|
||||
$compiler->raw('] ?? null) : null)');
|
||||
|
||||
return;
|
||||
@@ -91,7 +91,7 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest
|
||||
->raw($var)
|
||||
->raw('[')
|
||||
;
|
||||
$this->compileArrayKey($compiler);
|
||||
$this->compileArrayKey($compiler, $var);
|
||||
$compiler->raw('] ?? null) : ');
|
||||
}
|
||||
|
||||
@@ -177,9 +177,11 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest
|
||||
|
||||
/**
|
||||
* Coerces a Stringable array key to string so the optimized path matches
|
||||
* CoreExtension::getAttribute(); scalars are left to PHP's native offset coercion.
|
||||
* CoreExtension::getAttribute(): only arrays coerce the key, while ArrayAccess
|
||||
* objects (e.g. SplObjectStorage) receive it untouched. Scalars are left to
|
||||
* PHP's native offset coercion.
|
||||
*/
|
||||
private function compileArrayKey(Compiler $compiler): void
|
||||
private function compileArrayKey(Compiler $compiler, string $var): void
|
||||
{
|
||||
$attribute = $this->getNode('attribute');
|
||||
|
||||
@@ -193,7 +195,7 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest
|
||||
$compiler
|
||||
->raw('(('.$key.' = ')
|
||||
->subcompile($attribute)
|
||||
->raw(') instanceof \Stringable ? (string) '.$key.' : '.$key.')')
|
||||
->raw(') instanceof \Stringable && is_array('.$var.') ? (string) '.$key.' : '.$key.')')
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -284,6 +284,29 @@ class TemplateTest extends TestCase
|
||||
yield 'strict' => [true];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getStrictVariablesModes
|
||||
*/
|
||||
#[DataProvider('getStrictVariablesModes')]
|
||||
public function testArrayAccessWithObjectKeyKeepsTheObjectKey(bool $strict)
|
||||
{
|
||||
$twig = new Environment(new ArrayLoader(['index' => '{{ data[object] }}']), [
|
||||
'strict_variables' => $strict,
|
||||
'autoescape' => false,
|
||||
]);
|
||||
|
||||
$object = new class implements \Stringable {
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'string';
|
||||
}
|
||||
};
|
||||
$data = new \SplObjectStorage();
|
||||
$data[$object] = 'value';
|
||||
|
||||
$this->assertSame('value', $twig->render('index', ['data' => $data, 'object' => $object]));
|
||||
}
|
||||
|
||||
public function testArrayAccessWithStringableKeyIsCheckedBySandbox()
|
||||
{
|
||||
$object = new class implements \Stringable {
|
||||
|
||||
Reference in New Issue
Block a user