1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Twig\Node\Expression; 13 14use Twig\Compiler; 15use Twig\Node\Expression\Binary\AndBinary; 16use Twig\Node\Expression\Test\DefinedTest; 17use Twig\Node\Expression\Test\NullTest; 18use Twig\Node\Expression\Unary\NotUnary; 19use Twig\Node\Node; 20 21class NullCoalesceExpression extends ConditionalExpression 22{ 23 public function __construct(Node $left, Node $right, int $lineno) 24 { 25 $test = new DefinedTest(clone $left, 'defined', new Node(), $left->getTemplateLine()); 26 // for "block()", we don't need the null test as the return value is always a string 27 if (!$left instanceof BlockReferenceExpression) { 28 $test = new AndBinary( 29 $test, 30 new NotUnary(new NullTest($left, 'null', new Node(), $left->getTemplateLine()), $left->getTemplateLine()), 31 $left->getTemplateLine() 32 ); 33 } 34 35 parent::__construct($test, $left, $right, $lineno); 36 } 37 38 public function compile(Compiler $compiler) 39 { 40 /* 41 * This optimizes only one case. PHP 7 also supports more complex expressions 42 * that can return null. So, for instance, if log is defined, log("foo") ?? "..." works, 43 * but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced 44 * cases might be implemented as an optimizer node visitor, but has not been done 45 * as benefits are probably not worth the added complexity. 46 */ 47 if ($this->getNode('expr2') instanceof NameExpression) { 48 $this->getNode('expr2')->setAttribute('always_defined', true); 49 $compiler 50 ->raw('((') 51 ->subcompile($this->getNode('expr2')) 52 ->raw(') ?? (') 53 ->subcompile($this->getNode('expr3')) 54 ->raw('))') 55 ; 56 } else { 57 parent::compile($compiler); 58 } 59 } 60} 61 62class_alias('Twig\Node\Expression\NullCoalesceExpression', 'Twig_Node_Expression_NullCoalesce'); 63