[ Index ]

PHP Cross Reference of phpBB-3.3.3-deutsch

title

Body

[close]

/vendor/twig/twig/src/NodeVisitor/ -> OptimizerNodeVisitor.php (source)

   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      const OPTIMIZE_ALL = -1;
  41      const OPTIMIZE_NONE = 0;
  42      const OPTIMIZE_FOR = 2;
  43      const OPTIMIZE_RAW_FILTER = 4;
  44      // obsolete, does not do anything
  45      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');


Generated: Sun Feb 14 20:08:31 2021 Cross-referenced by PHPXref 0.7.1