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 12namespace Twig; 13 14use Twig\Node\Node; 15use Twig\NodeVisitor\NodeVisitorInterface; 16 17/** 18 * A node traverser. 19 * 20 * It visits all nodes and their children and calls the given visitor for each. 21 * 22 * @author Fabien Potencier <fabien@symfony.com> 23 */ 24final class NodeTraverser 25{ 26 private $env; 27 private $visitors = []; 28 29 /** 30 * @param NodeVisitorInterface[] $visitors 31 */ 32 public function __construct(Environment $env, array $visitors = []) 33 { 34 $this->env = $env; 35 foreach ($visitors as $visitor) { 36 $this->addVisitor($visitor); 37 } 38 } 39 40 public function addVisitor(NodeVisitorInterface $visitor): void 41 { 42 $this->visitors[$visitor->getPriority()][] = $visitor; 43 } 44 45 /** 46 * Traverses a node and calls the registered visitors. 47 */ 48 public function traverse(Node $node): Node 49 { 50 ksort($this->visitors); 51 foreach ($this->visitors as $visitors) { 52 foreach ($visitors as $visitor) { 53 $node = $this->traverseForVisitor($visitor, $node); 54 } 55 } 56 57 return $node; 58 } 59 60 private function traverseForVisitor(NodeVisitorInterface $visitor, Node $node): ?Node 61 { 62 $node = $visitor->enterNode($node, $this->env); 63 64 foreach ($node as $k => $n) { 65 if (null !== $m = $this->traverseForVisitor($visitor, $n)) { 66 if ($m !== $n) { 67 $node->setNode($k, $m); 68 } 69 } else { 70 $node->removeNode($k); 71 } 72 } 73 74 return $visitor->leaveNode($node, $this->env); 75 } 76} 77