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(\Twig_NodeInterface $left, \Twig_NodeInterface $right, $lineno) 24 { 25 $test = new AndBinary( 26 new DefinedTest(clone $left, 'defined', new Node(), $left->getTemplateLine()), 27 new NotUnary(new NullTest($left, 'null', new Node(), $left->getTemplateLine()), $left->getTemplateLine()), 28 $left->getTemplateLine() 29 ); 30 31 parent::__construct($test, $left, $right, $lineno); 32 } 33 34 public function compile(Compiler $compiler) 35 { 36 /* 37 * This optimizes only one case. PHP 7 also supports more complex expressions 38 * that can return null. So, for instance, if log is defined, log("foo") ?? "..." works, 39 * but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced 40 * cases might be implemented as an optimizer node visitor, but has not been done 41 * as benefits are probably not worth the added complexity. 42 */ 43 if (\PHP_VERSION_ID >= 70000 && $this->getNode('expr2') instanceof NameExpression) { 44 $this->getNode('expr2')->setAttribute('always_defined', true); 45 $compiler 46 ->raw('((') 47 ->subcompile($this->getNode('expr2')) 48 ->raw(') ?? (') 49 ->subcompile($this->getNode('expr3')) 50 ->raw('))') 51 ; 52 } else { 53 parent::compile($compiler); 54 } 55 } 56} 57 58class_alias('Twig\Node\Expression\NullCoalesceExpression', 'Twig_Node_Expression_NullCoalesce'); 59