1919use Twig \Node \Expression \Test \DefinedTest ;
2020use Twig \Node \Expression \Test \NullTest ;
2121use Twig \Node \Expression \Unary \NotUnary ;
22- use Twig \Node \Expression \Variable \ContextVariable ;
2322use Twig \TwigTest ;
2423
2524final class NullCoalesceBinary extends AbstractBinary implements OperatorEscapeInterface
@@ -28,47 +27,31 @@ public function __construct(AbstractExpression $left, AbstractExpression $right,
2827 {
2928 parent ::__construct ($ left , $ right , $ lineno );
3029
31- if (!$ left instanceof ContextVariable) {
32- $ test = new DefinedTest (clone $ left , new TwigTest ('defined ' ), new EmptyNode (), $ left ->getTemplateLine ());
33- // for "block()", we don't need the null test as the return value is always a string
34- if (!$ left instanceof BlockReferenceExpression) {
35- $ test = new AndBinary (
36- $ test ,
37- new NotUnary (new NullTest ($ left , new TwigTest ('null ' ), new EmptyNode (), $ left ->getTemplateLine ()), $ left ->getTemplateLine ()),
38- $ left ->getTemplateLine (),
39- );
40- }
41-
42- $ this ->setNode ('test ' , $ test );
43- } else {
44- $ left ->setAttribute ('always_defined ' , true );
30+ $ test = new DefinedTest (clone $ left , new TwigTest ('defined ' ), new EmptyNode (), $ left ->getTemplateLine ());
31+ // for "block()", we don't need the null test as the return value is always a string
32+ if (!$ left instanceof BlockReferenceExpression) {
33+ $ test = new AndBinary (
34+ $ test ,
35+ new NotUnary (new NullTest ($ left , new TwigTest ('null ' ), new EmptyNode (), $ left ->getTemplateLine ()), $ left ->getTemplateLine ()),
36+ $ left ->getTemplateLine (),
37+ );
4538 }
39+
40+ $ left ->setAttribute ('always_defined ' , true );
41+ $ this ->setNode ('test ' , $ test );
4642 }
4743
4844 public function compile (Compiler $ compiler ): void
4945 {
50- /*
51- * This optimizes only one case. PHP 7 also supports more complex expressions
52- * that can return null. So, for instance, if log is defined, log("foo") ?? "..." works,
53- * but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced
54- * cases might be implemented as an optimizer node visitor, but has not been done
55- * as benefits are probably not worth the added complexity.
56- */
57- if ($ this ->hasNode ('test ' )) {
58- $ compiler
59- ->raw ('(( ' )
60- ->subcompile ($ this ->getNode ('test ' ))
61- ->raw (') ? ( ' )
62- ->subcompile ($ this ->getNode ('left ' ))
63- ->raw (') : ( ' )
64- ->subcompile ($ this ->getNode ('right ' ))
65- ->raw (')) ' )
66- ;
67-
68- return ;
69- }
70-
71- parent ::compile ($ compiler );
46+ $ compiler
47+ ->raw ('(( ' )
48+ ->subcompile ($ this ->getNode ('test ' ))
49+ ->raw (') ? ( ' )
50+ ->subcompile ($ this ->getNode ('left ' ))
51+ ->raw (') : ( ' )
52+ ->subcompile ($ this ->getNode ('right ' ))
53+ ->raw (')) ' )
54+ ;
7255 }
7356
7457 public function operator (Compiler $ compiler ): Compiler
@@ -78,6 +61,6 @@ public function operator(Compiler $compiler): Compiler
7861
7962 public function getOperandNamesToEscape (): array
8063 {
81- return $ this -> hasNode ( ' test ' ) ? ['left ' , ' right ' ] : [ 'right ' ];
64+ return ['left ' , 'right ' ];
8265 }
8366}
0 commit comments