[ Index ] |
PHP Cross Reference of phpBB-3.3.11-deutsch |
[Summary view] [Print] [Text view]
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 12 namespace Twig\NodeVisitor; 13 14 use Twig\Environment; 15 use Twig\Node\BlockReferenceNode; 16 use Twig\Node\Expression\BlockReferenceExpression; 17 use Twig\Node\Expression\ConstantExpression; 18 use Twig\Node\Expression\FilterExpression; 19 use Twig\Node\Expression\FunctionExpression; 20 use Twig\Node\Expression\GetAttrExpression; 21 use Twig\Node\Expression\NameExpression; 22 use Twig\Node\Expression\ParentExpression; 23 use Twig\Node\ForNode; 24 use Twig\Node\IncludeNode; 25 use Twig\Node\Node; 26 use Twig\Node\PrintNode; 27 28 /** 29 * Tries to optimize the AST. 30 * 31 * This visitor is always the last registered one. 32 * 33 * You can configure which optimizations you want to activate via the 34 * optimizer mode. 35 * 36 * @author Fabien Potencier <fabien@symfony.com> 37 */ 38 final class OptimizerNodeVisitor extends AbstractNodeVisitor 39 { 40 public const OPTIMIZE_ALL = -1; 41 public const OPTIMIZE_NONE = 0; 42 public const OPTIMIZE_FOR = 2; 43 public const OPTIMIZE_RAW_FILTER = 4; 44 // obsolete, does not do anything 45 public const OPTIMIZE_VAR_ACCESS = 8; 46 47 private $loops = []; 48 private $loopsTargets = []; 49 private $optimizers; 50 51 /** 52 * @param int $optimizers The optimizer mode 53 */ 54 public function __construct(int $optimizers = -1) 55 { 56 if (!\is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) { 57 throw new \InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); 58 } 59 60 $this->optimizers = $optimizers; 61 } 62 63 protected function doEnterNode(Node $node, Environment $env) 64 { 65 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { 66 $this->enterOptimizeFor($node, $env); 67 } 68 69 return $node; 70 } 71 72 protected function doLeaveNode(Node $node, Environment $env) 73 { 74 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { 75 $this->leaveOptimizeFor($node, $env); 76 } 77 78 if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) { 79 $node = $this->optimizeRawFilter($node, $env); 80 } 81 82 $node = $this->optimizePrintNode($node, $env); 83 84 return $node; 85 } 86 87 /** 88 * Optimizes print nodes. 89 * 90 * It replaces: 91 * 92 * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" 93 */ 94 private function optimizePrintNode(Node $node, Environment $env): Node 95 { 96 if (!$node instanceof PrintNode) { 97 return $node; 98 } 99 100 $exprNode = $node->getNode('expr'); 101 if ( 102 $exprNode instanceof BlockReferenceExpression || 103 $exprNode instanceof ParentExpression 104 ) { 105 $exprNode->setAttribute('output', true); 106 107 return $exprNode; 108 } 109 110 return $node; 111 } 112 113 /** 114 * Removes "raw" filters. 115 */ 116 private function optimizeRawFilter(Node $node, Environment $env): Node 117 { 118 if ($node instanceof FilterExpression && 'raw' == $node->getNode('filter')->getAttribute('value')) { 119 return $node->getNode('node'); 120 } 121 122 return $node; 123 } 124 125 /** 126 * Optimizes "for" tag by removing the "loop" variable creation whenever possible. 127 */ 128 private function enterOptimizeFor(Node $node, Environment $env) 129 { 130 if ($node instanceof ForNode) { 131 // disable the loop variable by default 132 $node->setAttribute('with_loop', false); 133 array_unshift($this->loops, $node); 134 array_unshift($this->loopsTargets, $node->getNode('value_target')->getAttribute('name')); 135 array_unshift($this->loopsTargets, $node->getNode('key_target')->getAttribute('name')); 136 } elseif (!$this->loops) { 137 // we are outside a loop 138 return; 139 } 140 141 // when do we need to add the loop variable back? 142 143 // the loop variable is referenced for the current loop 144 elseif ($node instanceof NameExpression && 'loop' === $node->getAttribute('name')) { 145 $node->setAttribute('always_defined', true); 146 $this->addLoopToCurrent(); 147 } 148 149 // optimize access to loop targets 150 elseif ($node instanceof NameExpression && \in_array($node->getAttribute('name'), $this->loopsTargets)) { 151 $node->setAttribute('always_defined', true); 152 } 153 154 // block reference 155 elseif ($node instanceof BlockReferenceNode || $node instanceof BlockReferenceExpression) { 156 $this->addLoopToCurrent(); 157 } 158 159 // include without the only attribute 160 elseif ($node instanceof IncludeNode && !$node->getAttribute('only')) { 161 $this->addLoopToAll(); 162 } 163 164 // include function without the with_context=false parameter 165 elseif ($node instanceof FunctionExpression 166 && 'include' === $node->getAttribute('name') 167 && (!$node->getNode('arguments')->hasNode('with_context') 168 || false !== $node->getNode('arguments')->getNode('with_context')->getAttribute('value') 169 ) 170 ) { 171 $this->addLoopToAll(); 172 } 173 174 // the loop variable is referenced via an attribute 175 elseif ($node instanceof GetAttrExpression 176 && (!$node->getNode('attribute') instanceof ConstantExpression 177 || 'parent' === $node->getNode('attribute')->getAttribute('value') 178 ) 179 && (true === $this->loops[0]->getAttribute('with_loop') 180 || ($node->getNode('node') instanceof NameExpression 181 && 'loop' === $node->getNode('node')->getAttribute('name') 182 ) 183 ) 184 ) { 185 $this->addLoopToAll(); 186 } 187 } 188 189 /** 190 * Optimizes "for" tag by removing the "loop" variable creation whenever possible. 191 */ 192 private function leaveOptimizeFor(Node $node, Environment $env) 193 { 194 if ($node instanceof ForNode) { 195 array_shift($this->loops); 196 array_shift($this->loopsTargets); 197 array_shift($this->loopsTargets); 198 } 199 } 200 201 private function addLoopToCurrent() 202 { 203 $this->loops[0]->setAttribute('with_loop', true); 204 } 205 206 private function addLoopToAll() 207 { 208 foreach ($this->loops as $loop) { 209 $loop->setAttribute('with_loop', true); 210 } 211 } 212 213 public function getPriority() 214 { 215 return 255; 216 } 217 } 218 219 class_alias('Twig\NodeVisitor\OptimizerNodeVisitor', 'Twig_NodeVisitor_Optimizer');
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Nov 4 14:26:03 2023 | Cross-referenced by PHPXref 0.7.1 |