Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
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 |
OptimizerNodeVisitor.php
001 <?php
002
003 /*
004 * This file is part of Twig.
005 *
006 * (c) 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 namespace Twig\NodeVisitor;
013
014 use Twig\Environment;
015 use Twig\Node\BlockReferenceNode;
016 use Twig\Node\Expression\BlockReferenceExpression;
017 use Twig\Node\Expression\ConstantExpression;
018 use Twig\Node\Expression\FilterExpression;
019 use Twig\Node\Expression\FunctionExpression;
020 use Twig\Node\Expression\GetAttrExpression;
021 use Twig\Node\Expression\NameExpression;
022 use Twig\Node\Expression\ParentExpression;
023 use Twig\Node\ForNode;
024 use Twig\Node\IncludeNode;
025 use Twig\Node\Node;
026 use Twig\Node\PrintNode;
027
028 /**
029 * Tries to optimize the AST.
030 *
031 * This visitor is always the last registered one.
032 *
033 * You can configure which optimizations you want to activate via the
034 * optimizer mode.
035 *
036 * @author Fabien Potencier <fabien@symfony.com>
037 */
038 final class OptimizerNodeVisitor extends AbstractNodeVisitor
039 {
040 public const OPTIMIZE_ALL = -1;
041 public const OPTIMIZE_NONE = 0;
042 public const OPTIMIZE_FOR = 2;
043 public const OPTIMIZE_RAW_FILTER = 4;
044 // obsolete, does not do anything
045 public const OPTIMIZE_VAR_ACCESS = 8;
046
047 private $loops = [];
048 private $loopsTargets = [];
049 private $optimizers;
050
051 /**
052 * @param int $optimizers The optimizer mode
053 */
054 public function __construct(int $optimizers = -1)
055 {
056 if (!\is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
057 throw new \InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
058 }
059
060 $this->optimizers = $optimizers;
061 }
062
063 protected function doEnterNode(Node $node, Environment $env)
064 {
065 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
066 $this->enterOptimizeFor($node, $env);
067 }
068
069 return $node;
070 }
071
072 protected function doLeaveNode(Node $node, Environment $env)
073 {
074 if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
075 $this->leaveOptimizeFor($node, $env);
076 }
077
078 if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
079 $node = $this->optimizeRawFilter($node, $env);
080 }
081
082 $node = $this->optimizePrintNode($node, $env);
083
084 return $node;
085 }
086
087 /**
088 * Optimizes print nodes.
089 *
090 * It replaces:
091 *
092 * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
093 */
094 private function optimizePrintNode(Node $node, Environment $env): Node
095 {
096 if (!$node instanceof PrintNode) {
097 return $node;
098 }
099
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');
220