[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/vendor/twig/twig/lib/Twig/NodeVisitor/ -> Optimizer.php (source)

   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  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1