[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of Twig. 5 * 6 * (c) 2010 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 /** 13 * Twig_NodeVisitor_Optimizer tries to optimizes the AST. 14 * 15 * This visitor is always the last registered one. 16 * 17 * You can configure which optimizations you want to activate via the 18 * optimizer mode. 19 * 20 * @author Fabien Potencier <fabien@symfony.com> 21 */ 22 class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor 23 { 24 const OPTIMIZE_ALL = -1; 25 const OPTIMIZE_NONE = 0; 26 const OPTIMIZE_FOR = 2; 27 const OPTIMIZE_RAW_FILTER = 4; 28 const OPTIMIZE_VAR_ACCESS = 8; 29 30 protected $loops = array(); 31 protected $loopsTargets = array(); 32 protected $optimizers; 33 protected $prependedNodes = array(); 34 protected $inABody = false; 35 36 /** 37 * Constructor. 38 * 39 * @param int $optimizers The optimizer mode 40 */ 41 public function __construct($optimizers = -1) 42 { 43 if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) { 44 throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); 45 } 46 47 $this->optimizers = $optimizers; 48 } 49 50 /** 51 * {@inheritdoc} 52 */ 53 protected function doEnterNode(Twig_Node $node, Twig_Environment $env) 54 { 55 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { 56 $this->enterOptimizeFor($node, $env); 57 } 58 59 if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { 60 if ($this->inABody) { 61 if (!$node instanceof Twig_Node_Expression) { 62 if (get_class($node) !== 'Twig_Node') { 63 array_unshift($this->prependedNodes, array()); 64 } 65 } else { 66 $node = $this->optimizeVariables($node, $env); 67 } 68 } elseif ($node instanceof Twig_Node_Body) { 69 $this->inABody = true; 70 } 71 } 72 73 return $node; 74 } 75 76 /** 77 * {@inheritdoc} 78 */ 79 protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) 80 { 81 $expression = $node instanceof Twig_Node_Expression; 82 83 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { 84 $this->leaveOptimizeFor($node, $env); 85 } 86 87 if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) { 88 $node = $this->optimizeRawFilter($node, $env); 89 } 90 91 $node = $this->optimizePrintNode($node, $env); 92 93 if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { 94 if ($node instanceof Twig_Node_Body) { 95 $this->inABody = false; 96 } elseif ($this->inABody) { 97 if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) { 98 $nodes = array(); 99 foreach (array_unique($prependedNodes) as $name) { 100 $nodes[] = new Twig_Node_SetTemp($name, $node->getLine()); 101 } 102 103 $nodes[] = $node; 104 $node = new Twig_Node($nodes); 105 } 106 } 107 } 108 109 return $node; 110 } 111 112 protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env) 113 { 114 if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) { 115 $this->prependedNodes[0][] = $node->getAttribute('name'); 116 117 return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine()); 118 } 119 120 return $node; 121 } 122 123 /** 124 * Optimizes print nodes. 125 * 126 * It replaces: 127 * 128 * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" 129 * 130 * @param Twig_NodeInterface $node A Node 131 * @param Twig_Environment $env The current Twig environment 132 * 133 * @return Twig_NodeInterface 134 */ 135 protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env) 136 { 137 if (!$node instanceof Twig_Node_Print) { 138 return $node; 139 } 140 141 if ( 142 $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference || 143 $node->getNode('expr') instanceof Twig_Node_Expression_Parent 144 ) { 145 $node->getNode('expr')->setAttribute('output', true); 146 147 return $node->getNode('expr'); 148 } 149 150 return $node; 151 } 152 153 /** 154 * Removes "raw" filters. 155 * 156 * @param Twig_NodeInterface $node A Node 157 * @param Twig_Environment $env The current Twig environment 158 * 159 * @return Twig_NodeInterface 160 */ 161 protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env) 162 { 163 if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) { 164 return $node->getNode('node'); 165 } 166 167 return $node; 168 } 169 170 /** 171 * Optimizes "for" tag by removing the "loop" variable creation whenever possible. 172 * 173 * @param Twig_NodeInterface $node A Node 174 * @param Twig_Environment $env The current Twig environment 175 */ 176 protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) 177 { 178 if ($node instanceof Twig_Node_For) { 179 // disable the loop variable by default 180 $node->setAttribute('with_loop', false); 181 array_unshift($this->loops, $node); 182 array_unshift($this->loopsTargets, $node->getNode('value_target')->getAttribute('name')); 183 array_unshift($this->loopsTargets, $node->getNode('key_target')->getAttribute('name')); 184 } elseif (!$this->loops) { 185 // we are outside a loop 186 return; 187 } 188 189 // when do we need to add the loop variable back? 190 191 // the loop variable is referenced for the current loop 192 elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) { 193 $node->setAttribute('always_defined', true); 194 $this->addLoopToCurrent(); 195 } 196 197 // optimize access to loop targets 198 elseif ($node instanceof Twig_Node_Expression_Name && in_array($node->getAttribute('name'), $this->loopsTargets)) { 199 $node->setAttribute('always_defined', true); 200 } 201 202 // block reference 203 elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) { 204 $this->addLoopToCurrent(); 205 } 206 207 // include without the only attribute 208 elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) { 209 $this->addLoopToAll(); 210 } 211 212 // include function without the with_context=false parameter 213 elseif ($node instanceof Twig_Node_Expression_Function 214 && 'include' === $node->getAttribute('name') 215 && (!$node->getNode('arguments')->hasNode('with_context') 216 || false !== $node->getNode('arguments')->getNode('with_context')->getAttribute('value') 217 ) 218 ) { 219 $this->addLoopToAll(); 220 } 221 222 // the loop variable is referenced via an attribute 223 elseif ($node instanceof Twig_Node_Expression_GetAttr 224 && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant 225 || 'parent' === $node->getNode('attribute')->getAttribute('value') 226 ) 227 && (true === $this->loops[0]->getAttribute('with_loop') 228 || ($node->getNode('node') instanceof Twig_Node_Expression_Name 229 && 'loop' === $node->getNode('node')->getAttribute('name') 230 ) 231 ) 232 ) { 233 $this->addLoopToAll(); 234 } 235 } 236 237 /** 238 * Optimizes "for" tag by removing the "loop" variable creation whenever possible. 239 * 240 * @param Twig_NodeInterface $node A Node 241 * @param Twig_Environment $env The current Twig environment 242 */ 243 protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) 244 { 245 if ($node instanceof Twig_Node_For) { 246 array_shift($this->loops); 247 array_shift($this->loopsTargets); 248 array_shift($this->loopsTargets); 249 } 250 } 251 252 protected function addLoopToCurrent() 253 { 254 $this->loops[0]->setAttribute('with_loop', true); 255 } 256 257 protected function addLoopToAll() 258 { 259 foreach ($this->loops as $loop) { 260 $loop->setAttribute('with_loop', true); 261 } 262 } 263 264 /** 265 * {@inheritdoc} 266 */ 267 public function getPriority() 268 { 269 return 255; 270 } 271 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |