Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Optimizer.php
001 <?php
002
003 /*
004 * This file is part of Twig.
005 *
006 * (c) 2010 Fabien Potencier
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 /**
013 * Twig_NodeVisitor_Optimizer tries to optimizes the AST.
014 *
015 * This visitor is always the last registered one.
016 *
017 * You can configure which optimizations you want to activate via the
018 * optimizer mode.
019 *
020 * @author Fabien Potencier <fabien@symfony.com>
021 */
022 class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor
023 {
024 const OPTIMIZE_ALL = -1;
025 const OPTIMIZE_NONE = 0;
026 const OPTIMIZE_FOR = 2;
027 const OPTIMIZE_RAW_FILTER = 4;
028 const OPTIMIZE_VAR_ACCESS = 8;
029
030 protected $loops = array();
031 protected $loopsTargets = array();
032 protected $optimizers;
033 protected $prependedNodes = array();
034 protected $inABody = false;
035
036 /**
037 * Constructor.
038 *
039 * @param int $optimizers The optimizer mode
040 */
041 public function __construct($optimizers = -1)
042 {
043 if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
044 throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
045 }
046
047 $this->optimizers = $optimizers;
048 }
049
050 /**
051 * {@inheritdoc}
052 */
053 protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
054 {
055 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
056 $this->enterOptimizeFor($node, $env);
057 }
058
059 if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
060 if ($this->inABody) {
061 if (!$node instanceof Twig_Node_Expression) {
062 if (get_class($node) !== 'Twig_Node') {
063 array_unshift($this->prependedNodes, array());
064 }
065 } else {
066 $node = $this->optimizeVariables($node, $env);
067 }
068 } elseif ($node instanceof Twig_Node_Body) {
069 $this->inABody = true;
070 }
071 }
072
073 return $node;
074 }
075
076 /**
077 * {@inheritdoc}
078 */
079 protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
080 {
081 $expression = $node instanceof Twig_Node_Expression;
082
083 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
084 $this->leaveOptimizeFor($node, $env);
085 }
086
087 if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
088 $node = $this->optimizeRawFilter($node, $env);
089 }
090
091 $node = $this->optimizePrintNode($node, $env);
092
093 if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
094 if ($node instanceof Twig_Node_Body) {
095 $this->inABody = false;
096 } elseif ($this->inABody) {
097 if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
098 $nodes = array();
099 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 }
272