From efd12ef0ccfb9ddaf310f0fc3029ca198076af8f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 2 Jan 2025 11:17:57 +0100 Subject: [PATCH] Optimize NameExpression compilation --- src/Node/Expression/NameExpression.php | 2 +- .../Variable/ContextVariableTest.php | 49 ++++++++++++++----- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/Node/Expression/NameExpression.php b/src/Node/Expression/NameExpression.php index 78ae51f0334..2872ba413ba 100644 --- a/src/Node/Expression/NameExpression.php +++ b/src/Node/Expression/NameExpression.php @@ -39,7 +39,7 @@ public function compile(Compiler $compiler): void $compiler->addDebugInfo($this); if ($this->getAttribute('is_defined_test')) { - if (isset($this->specialVars[$name])) { + if (isset($this->specialVars[$name]) || $this->getAttribute('always_defined')) { $compiler->repr(true); } elseif (\PHP_VERSION_ID >= 70400) { $compiler diff --git a/tests/Node/Expression/Variable/ContextVariableTest.php b/tests/Node/Expression/Variable/ContextVariableTest.php index be9f6917b05..46ab171a043 100644 --- a/tests/Node/Expression/Variable/ContextVariableTest.php +++ b/tests/Node/Expression/Variable/ContextVariableTest.php @@ -27,20 +27,47 @@ public function testConstructor() public static function provideTests(): iterable { - $node = new ContextVariable('foo', 1); - $self = new ContextVariable('_self', 1); - $context = new ContextVariable('_context', 1); + // special variables + foreach (['_self' => '$this->getTemplateName()', '_context' => '$context', '_charset' => '$this->env->getCharset()'] as $special => $compiled) { + $node = new ContextVariable($special, 1); + yield $special => [$node, "// line 1\n$compiled"]; + $node = new ContextVariable($special, 1); + $node->setAttribute('is_defined_test', true); + yield $special.'_defined_test' => [$node, "// line 1\ntrue"]; + } - $env = new Environment(new ArrayLoader(), ['strict_variables' => true]); - $env1 = new Environment(new ArrayLoader(), ['strict_variables' => false]); + $env = new Environment(new ArrayLoader(), ['strict_variables' => false]); + $envStrict = new Environment(new ArrayLoader(), ['strict_variables' => true]); + // regular + $node = new ContextVariable('foo', 1); $output = '(isset($context["foo"]) || array_key_exists("foo", $context) ? $context["foo"] : (function () { throw new RuntimeError(\'Variable "foo" does not exist.\', 1, $this->source); })())'; + yield 'strict' => [$node, "// line 1\n".$output, $envStrict]; + yield 'non_strict' => [$node, self::createVariableGetter('foo', 1), $env]; - return [ - [$node, "// line 1\n".$output, $env], - [$node, self::createVariableGetter('foo', 1), $env1], - [$self, "// line 1\n\$this->getTemplateName()"], - [$context, "// line 1\n\$context"], - ]; + // ignore strict check + $node = new ContextVariable('foo', 1); + $node->setAttribute('ignore_strict_check', true); + yield 'ignore_strict_check_strict' => [$node, "// line 1\n(\$context[\"foo\"] ?? null)", $envStrict]; + yield 'ignore_strict_check_non_strict' => [$node, "// line 1\n(\$context[\"foo\"] ?? null)", $env]; + + // always defined + $node = new ContextVariable('foo', 1); + $node->setAttribute('always_defined', true); + yield 'always_defined_strict' => [$node, "// line 1\n\$context[\"foo\"]", $envStrict]; + yield 'always_defined_non_strict' => [$node, "// line 1\n\$context[\"foo\"]", $env]; + + // is defined test + $node = new ContextVariable('foo', 1); + $node->setAttribute('is_defined_test', true); + yield 'is_defined_test_strict' => [$node, "// line 1\narray_key_exists(\"foo\", \$context)", $envStrict]; + yield 'is_defined_test_non_strict' => [$node, "// line 1\narray_key_exists(\"foo\", \$context)", $env]; + + // is defined test // always defined + $node = new ContextVariable('foo', 1); + $node->setAttribute('is_defined_test', true); + $node->setAttribute('always_defined', true); + yield 'is_defined_test_always_defined_strict' => [$node, "// line 1\ntrue", $envStrict]; + yield 'is_defined_test_always_defined_non_strict' => [$node, "// line 1\ntrue", $env]; } }