ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Optimizer.php
Go to the documentation of this file.
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 
25 {
26  const OPTIMIZE_ALL = -1;
27  const OPTIMIZE_NONE = 0;
28  const OPTIMIZE_FOR = 2;
31 
32  protected $loops = array();
33  protected $loopsTargets = array();
34  protected $optimizers;
35  protected $prependedNodes = array();
36  protected $inABody = false;
37 
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  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
51  {
52  if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
53  $this->enterOptimizeFor($node, $env);
54  }
55 
56  if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('Twig_Extension_Sandbox')) {
57  if ($this->inABody) {
58  if (!$node instanceof Twig_Node_Expression) {
59  if ('Twig_Node' !== get_class($node)) {
60  array_unshift($this->prependedNodes, array());
61  }
62  } else {
63  $node = $this->optimizeVariables($node, $env);
64  }
65  } elseif ($node instanceof Twig_Node_Body) {
66  $this->inABody = true;
67  }
68  }
69 
70  return $node;
71  }
72 
73  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
74  {
75  $expression = $node instanceof Twig_Node_Expression;
76 
77  if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
78  $this->leaveOptimizeFor($node, $env);
79  }
80 
81  if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
82  $node = $this->optimizeRawFilter($node, $env);
83  }
84 
85  $node = $this->optimizePrintNode($node, $env);
86 
87  if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('Twig_Extension_Sandbox')) {
88  if ($node instanceof Twig_Node_Body) {
89  $this->inABody = false;
90  } elseif ($this->inABody) {
91  if (!$expression && 'Twig_Node' !== get_class($node) && $prependedNodes = array_shift($this->prependedNodes)) {
92  $nodes = array();
93  foreach (array_unique($prependedNodes) as $name) {
94  $nodes[] = new Twig_Node_SetTemp($name, $node->getTemplateLine());
95  }
96 
97  $nodes[] = $node;
98  $node = new Twig_Node($nodes);
99  }
100  }
101  }
102 
103  return $node;
104  }
105 
107  {
108  if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
109  $this->prependedNodes[0][] = $node->getAttribute('name');
110 
111  return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getTemplateLine());
112  }
113 
114  return $node;
115  }
116 
127  {
128  if (!$node instanceof Twig_Node_Print) {
129  return $node;
130  }
131 
132  $exprNode = $node->getNode('expr');
133  if (
134  $exprNode instanceof Twig_Node_Expression_BlockReference ||
135  $exprNode instanceof Twig_Node_Expression_Parent
136  ) {
137  $exprNode->setAttribute('output', true);
138 
139  return $exprNode;
140  }
141 
142  return $node;
143  }
144 
151  {
152  if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
153  return $node->getNode('node');
154  }
155 
156  return $node;
157  }
158 
163  {
164  if ($node instanceof Twig_Node_For) {
165  // disable the loop variable by default
166  $node->setAttribute('with_loop', false);
167  array_unshift($this->loops, $node);
168  array_unshift($this->loopsTargets, $node->getNode('value_target')->getAttribute('name'));
169  array_unshift($this->loopsTargets, $node->getNode('key_target')->getAttribute('name'));
170  } elseif (!$this->loops) {
171  // we are outside a loop
172  return;
173  }
174 
175  // when do we need to add the loop variable back?
176 
177  // the loop variable is referenced for the current loop
178  elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
179  $node->setAttribute('always_defined', true);
180  $this->addLoopToCurrent();
181  }
182 
183  // optimize access to loop targets
184  elseif ($node instanceof Twig_Node_Expression_Name && in_array($node->getAttribute('name'), $this->loopsTargets)) {
185  $node->setAttribute('always_defined', true);
186  }
187 
188  // block reference
189  elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
190  $this->addLoopToCurrent();
191  }
192 
193  // include without the only attribute
194  elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
195  $this->addLoopToAll();
196  }
197 
198  // include function without the with_context=false parameter
199  elseif ($node instanceof Twig_Node_Expression_Function
200  && 'include' === $node->getAttribute('name')
201  && (!$node->getNode('arguments')->hasNode('with_context')
202  || false !== $node->getNode('arguments')->getNode('with_context')->getAttribute('value')
203  )
204  ) {
205  $this->addLoopToAll();
206  }
207 
208  // the loop variable is referenced via an attribute
209  elseif ($node instanceof Twig_Node_Expression_GetAttr
210  && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
211  || 'parent' === $node->getNode('attribute')->getAttribute('value')
212  )
213  && (true === $this->loops[0]->getAttribute('with_loop')
214  || ($node->getNode('node') instanceof Twig_Node_Expression_Name
215  && 'loop' === $node->getNode('node')->getAttribute('name')
216  )
217  )
218  ) {
219  $this->addLoopToAll();
220  }
221  }
222 
227  {
228  if ($node instanceof Twig_Node_For) {
229  array_shift($this->loops);
230  array_shift($this->loopsTargets);
231  array_shift($this->loopsTargets);
232  }
233  }
234 
235  protected function addLoopToCurrent()
236  {
237  $this->loops[0]->setAttribute('with_loop', true);
238  }
239 
240  protected function addLoopToAll()
241  {
242  foreach ($this->loops as $loop) {
243  $loop->setAttribute('with_loop', true);
244  }
245  }
246 
247  public function getPriority()
248  {
249  return 255;
250  }
251 }
252 
253 class_alias('Twig_NodeVisitor_Optimizer', 'Twig\NodeVisitor\OptimizerNodeVisitor', false);
Represents a node in the AST.
optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env)
Removes "raw" filters.
Definition: Optimizer.php:150
Represents a node in the AST.
Definition: Node.php:18
Represents an include node.
Definition: Include.php:18
getPriority()
Returns the priority for this visitor.
Definition: Optimizer.php:247
Twig_NodeVisitor_Optimizer tries to optimizes the AST.
Definition: Optimizer.php:24
optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env)
Definition: Optimizer.php:106
Represents a block call node.
Abstract class for all nodes that represents an expression.
Definition: Expression.php:18
Represents a node that outputs an expression.
Definition: Print.php:18
$env
__construct($optimizers=-1)
Definition: Optimizer.php:41
Represents a parent node.
Definition: Parent.php:18
optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env)
Optimizes print nodes.
Definition: Optimizer.php:126
Represents a body node.
Definition: Body.php:17
Twig_BaseNodeVisitor can be used to make node visitors compatible with Twig 1.x and 2...
enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
Optimizes "for" tag by removing the "loop" variable creation whenever possible.
Definition: Optimizer.php:162
getTemplateLine()
Definition: Node.php:121
hasExtension($class)
Returns true if the given extension is registered.
Represents a block call node.
doLeaveNode(Twig_Node $node, Twig_Environment $env)
Definition: Optimizer.php:73
Represents a for node.
Definition: For.php:18
Stores the Twig configuration.
Definition: Environment.php:17
doEnterNode(Twig_Node $node, Twig_Environment $env)
Definition: Optimizer.php:50
leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
Optimizes "for" tag by removing the "loop" variable creation whenever possible.
Definition: Optimizer.php:226
isStrictVariables()
Checks if the strict_variables option is enabled.