From 6c485873b80b61309004efc9d19e6d9975f62bc2 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 9 Jul 2024 12:50:36 +0200 Subject: [PATCH] {default} is evaluated lazily --- src/Latte/Essential/Nodes/VarNode.php | 30 ++++++---------- tests/tags/expected/inheritance.1.parent.php | 4 ++- tests/tags/var.default.phpt | 37 +++++++++++++++----- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/Latte/Essential/Nodes/VarNode.php b/src/Latte/Essential/Nodes/VarNode.php index f7cb4c867..cd0a517cc 100644 --- a/src/Latte/Essential/Nodes/VarNode.php +++ b/src/Latte/Essential/Nodes/VarNode.php @@ -11,7 +11,6 @@ use Latte\Compiler\Nodes\Php\Expression\AssignNode; use Latte\Compiler\Nodes\Php\Expression\VariableNode; -use Latte\Compiler\Nodes\Php\ExpressionNode; use Latte\Compiler\Nodes\Php\Scalar\NullNode; use Latte\Compiler\Nodes\StatementNode; use Latte\Compiler\PrintContext; @@ -67,26 +66,19 @@ private static function parseAssignments(Tag $tag, bool $default): array public function print(PrintContext $context): string { $res = []; - if ($this->default) { - foreach ($this->assignments as $assign) { + foreach ($this->assignments as $assign) { + if ($this->default) { assert($assign->var instanceof VariableNode); - if ($assign->var->name instanceof ExpressionNode) { - $var = $assign->var->name->print($context); - } else { - $var = $context->encodeString($assign->var->name); - } - $res[] = $var . ' => ' . $assign->expr->print($context); + $res[] = $context->format( + '%node ??= array_key_exists(%raw, get_defined_vars()) ? %node : %node', + $assign->var, + $context->encodeString($assign->var->name), + $assign->var, + $assign->expr, + ); + } else { + $res[] = $assign->print($context); } - - return $context->format( - 'extract([%raw], EXTR_SKIP) %line;', - implode(', ', $res), - $this->position, - ); - } - - foreach ($this->assignments as $assign) { - $res[] = $assign->print($context); } return $context->format( diff --git a/tests/tags/expected/inheritance.1.parent.php b/tests/tags/expected/inheritance.1.parent.php index cdad6e4fa..1bf626393 100644 --- a/tests/tags/expected/inheritance.1.parent.php +++ b/tests/tags/expected/inheritance.1.parent.php @@ -53,7 +53,9 @@ public function prepare(): array { extract($this->params); - extract(['class' => null, 'namespace' => null, 'top' => true], EXTR_SKIP) /* line %d% */; + $class ??= array_key_exists('class', get_defined_vars()) ? $class : null; + $namespace ??= array_key_exists('namespace', get_defined_vars()) ? $namespace : null; + $top ??= array_key_exists('top', get_defined_vars()) ? $top : true /* line 1 */; return get_defined_vars(); } diff --git a/tests/tags/var.default.phpt b/tests/tags/var.default.phpt index e8e5bf843..dceda2de0 100644 --- a/tests/tags/var.default.phpt +++ b/tests/tags/var.default.phpt @@ -42,13 +42,37 @@ test('{var ...}', function () use ($latte) { test('{default ...}', function () use ($latte) { - Assert::contains("extract(['var' => null, 'var2' => null], EXTR_SKIP) /*", $latte->compile('{default $var, $var2}')); - Assert::contains("extract(['var' => 123], EXTR_SKIP) /*", $latte->compile('{default $var = 123}')); - Assert::contains("extract(['var1' => 123, 'var2' => 'nette framework'], EXTR_SKIP) /*", $latte->compile('{default $var1 = 123, $var2 = "nette framework"}')); + Assert::match(<<<'XX' + %A% + $var ??= array_key_exists('var', get_defined_vars()) ? $var : null; + $var2 ??= array_key_exists('var2', get_defined_vars()) ? $var2 : null /* line 1 */; + %A% + XX, $latte->compile('{default $var, $var2}')); + + Assert::contains( + '$var ??= array_key_exists(\'var\', get_defined_vars()) ? $var : 123 /* line 1 */;', + $latte->compile('{default $var = 123}'), + ); + + Assert::match(<<<'XX' + %A% + $var1 ??= array_key_exists('var1', get_defined_vars()) ? $var1 : 123; + $var2 ??= array_key_exists('var2', get_defined_vars()) ? $var2 : 'nette framework' /* line 1 */; + %A% + XX, $latte->compile('{default $var1 = 123, $var2 = "nette framework"}')); // types - Assert::contains("extract(['var' => 123], EXTR_SKIP) /*", $latte->compile('{default null|int|string[] $var = 123}')); - Assert::contains("extract(['var1' => 123, 'var2' => 'nette framework'], EXTR_SKIP) /*", $latte->compile('{default int|string[] $var1 = 123, ?class $var2 = "nette framework"}')); + Assert::contains( + '$var ??= array_key_exists(\'var\', get_defined_vars()) ? $var : 123 /* line 1 */;', + $latte->compile('{default null|int|string[] $var = 123}'), + ); + + Assert::match(<<<'XX' + %A% + $var1 ??= array_key_exists('var1', get_defined_vars()) ? $var1 : 123; + $var2 ??= array_key_exists('var2', get_defined_vars()) ? $var2 : 'nette framework' /* line 1 */; + %A% + XX, $latte->compile('{default int|string[] $var1 = 123, ?class $var2 = "nette framework"}')); // errors Assert::exception( @@ -62,7 +86,4 @@ test('{default ...}', function () use ($latte) { Latte\CompileException::class, 'Unexpected end in {default} (on line 1 at column 30)', ); - - // preprocess - Assert::contains("extract(['var1' => true ? 'a' : null], EXTR_SKIP) /*", $latte->compile('{default $var1 = true ? a}')); });