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