1: <?php declare(strict_types=1);
2:
3: namespace PhpParser\NodeVisitor;
4:
5: use PhpParser\Node;
6: use PhpParser\NodeVisitorAbstract;
7:
8: /**
9: * Visitor that connects a child node to its parent node
10: * as well as its sibling nodes.
11: *
12: * On the child node, the parent node can be accessed through
13: * <code>$node->getAttribute('parent')</code>, the previous
14: * node can be accessed through <code>$node->getAttribute('previous')</code>,
15: * and the next node can be accessed through <code>$node->getAttribute('next')</code>.
16: */
17: final class NodeConnectingVisitor extends NodeVisitorAbstract {
18: /**
19: * @var Node[]
20: */
21: private array $stack = [];
22:
23: /**
24: * @var ?Node
25: */
26: private $previous;
27:
28: public function beforeTraverse(array $nodes) {
29: $this->stack = [];
30: $this->previous = null;
31: }
32:
33: public function enterNode(Node $node) {
34: if (!empty($this->stack)) {
35: $node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
36: }
37:
38: if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) {
39: $node->setAttribute('previous', $this->previous);
40: $this->previous->setAttribute('next', $node);
41: }
42:
43: $this->stack[] = $node;
44: }
45:
46: public function leaveNode(Node $node) {
47: $this->previous = $node;
48:
49: array_pop($this->stack);
50: }
51: }
52: