From cfc3931f6e2ea1e1293113c5cd6dc85d22ebd55d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 10 Nov 2016 21:38:30 -0800 Subject: [PATCH] added support for PHP 7 null coalescing operator --- CHANGELOG | 1 + lib/Twig/Node/Expression/NullCoalesce.php | 23 ++++++++++++++ .../Node/Expression/NullCoalesceTest.php | 31 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 test/Twig/Tests/Node/Expression/NullCoalesceTest.php diff --git a/CHANGELOG b/CHANGELOG index cd701d3ff..cb3f937dd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.28.0 (2016-XX-XX) + * added support for the PHP 7 null coalescing operator for the ?? Twig implementation * exposed a way to access template data and methods in a portable way * changed context access to use the PHP 7 null coalescing operator when available * added the "with" tag diff --git a/lib/Twig/Node/Expression/NullCoalesce.php b/lib/Twig/Node/Expression/NullCoalesce.php index 65fa363b7..14f6358fd 100644 --- a/lib/Twig/Node/Expression/NullCoalesce.php +++ b/lib/Twig/Node/Expression/NullCoalesce.php @@ -20,4 +20,27 @@ class Twig_Node_Expression_NullCoalesce extends Twig_Node_Expression_Conditional parent::__construct($test, $left, $right, $lineno); } + + public function compile(Twig_Compiler $compiler) + { + /* + * This optimizes only one case. PHP 7 also supports more complex expressions + * that can return null. So, for instance, if log is defined, log("foo") ?? "..." works, + * but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced + * cases might be implemented as an optimizer node visitor, but has not been done + * as benefits are probably not worth the added complexity. + */ + if (PHP_VERSION_ID >= 70000 && $this->getNode('expr2') instanceof Twig_Node_Expression_Name) { + $this->getNode('expr2')->setAttribute('always_defined', true); + $compiler + ->raw('((') + ->subcompile($this->getNode('expr2')) + ->raw(') ?? (') + ->subcompile($this->getNode('expr3')) + ->raw('))') + ; + } else { + parent::compile($compiler); + } + } } diff --git a/test/Twig/Tests/Node/Expression/NullCoalesceTest.php b/test/Twig/Tests/Node/Expression/NullCoalesceTest.php new file mode 100644 index 000000000..a37490baf --- /dev/null +++ b/test/Twig/Tests/Node/Expression/NullCoalesceTest.php @@ -0,0 +1,31 @@ += 70000) { + $tests[] = array($node, "((// line 1\n\$context[\"foo\"]) ?? (2))"); + } elseif (PHP_VERSION_ID >= 50400) { + $tests[] = array($node, "(((// line 1\narray_key_exists(\"foo\", \$context) && !(null === (isset(\$context[\"foo\"]) ? \$context[\"foo\"] : null)))) ? ((isset(\$context[\"foo\"]) ? \$context[\"foo\"] : null)) : (2))"); + } else { + $tests[] = array($node, "(((// line 1\narray_key_exists(\"foo\", \$context) && !(null === \$this->getContext(\$context, \"foo\")))) ? (\$this->getContext(\$context, \"foo\")) : (2))"); + } + + return $tests; + } +}