blob: 47a2d5ca3ed25232a796d93e1584e725cc412087 [file] [log] [blame]
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001<?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}