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) 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 /** 61 * @return Node|null 62 */ 63 private function traverseForVisitor(NodeVisitorInterface $visitor, Node $node) 64 { 65 $node = $visitor->enterNode($node, $this->env); 66 67 foreach ($node as $k => $n) { 68 if (false !== ($m = $this->traverseForVisitor($visitor, $n)) && null !== $m) { 69 if ($m !== $n) { 70 $node->setNode($k, $m); 71 } 72 } else { 73 if (false === $m) { 74 @trigger_error('Returning "false" to remove a Node from NodeVisitorInterface::leaveNode() is deprecated since Twig version 2.9; return "null" instead.', \E_USER_DEPRECATED); 75 } 76 77 $node->removeNode($k); 78 } 79 } 80 81 return $visitor->leaveNode($node, $this->env); 82 } 83} 84 85class_alias('Twig\NodeTraverser', 'Twig_NodeTraverser'); 86