Chris@13: Frequently Asked Questions Chris@13: ========================== Chris@13: Chris@13: * [How can the parent of a node be obtained?](#how-can-the-parent-of-a-node-be-obtained) Chris@13: * [How can the next/previous sibling of a node be obtained?](#how-can-the-nextprevious-sibling-of-a-node-be-obtained) Chris@13: Chris@13: How can the parent of a node be obtained? Chris@13: ----- Chris@13: Chris@13: The AST does not store parent nodes by default. However, it is easy to add a custom parent node Chris@13: attribute using a custom node visitor: Chris@13: Chris@13: ```php Chris@13: use PhpParser\Node; Chris@13: use PhpParser\NodeVisitorAbstract; Chris@13: Chris@13: class ParentConnector extends NodeVisitorAbstract { Chris@13: private $stack; Chris@13: public function beforeTraverse(array $nodes) { Chris@13: $this->stack = []; Chris@13: } Chris@13: public function enterNode(Node $node) { Chris@13: if (!empty($this->stack)) { Chris@13: $node->setAttribute('parent', $this->stack[count($this->stack)-1]); Chris@13: } Chris@13: $this->stack[] = $node; Chris@13: } Chris@13: public function leaveNode(Node $node) { Chris@13: array_pop($this->stack); Chris@13: } Chris@13: } Chris@13: ``` Chris@13: Chris@13: After running this visitor, the parent node can be obtained through `$node->getAttribute('parent')`. Chris@13: Chris@13: How can the next/previous sibling of a node be obtained? Chris@13: ----- Chris@13: Chris@13: Again, siblings are not stored by default, but the visitor from the previous entry can be easily Chris@13: extended to store the previous / next node with a common parent as well: Chris@13: Chris@13: ```php Chris@13: use PhpParser\Node; Chris@13: use PhpParser\NodeVisitorAbstract; Chris@13: Chris@13: class NodeConnector extends NodeVisitorAbstract { Chris@13: private $stack; Chris@13: private $prev; Chris@13: public function beforeTraverse(array $nodes) { Chris@13: $this->stack = []; Chris@13: $this->prev = null; Chris@13: } Chris@13: public function enterNode(Node $node) { Chris@13: if (!empty($this->stack)) { Chris@13: $node->setAttribute('parent', $this->stack[count($this->stack)-1]); Chris@13: } Chris@13: if ($this->prev && $this->prev->getAttribute('parent') == $node->getAttribute('parent')) { Chris@13: $node->setAttribute('prev', $this->prev); Chris@13: $this->prev->setAttribute('next', $node); Chris@13: } Chris@13: $this->stack[] = $node; Chris@13: } Chris@13: public function leaveNode(Node $node) { Chris@13: $this->prev = $node; Chris@13: array_pop($this->stack); Chris@13: } Chris@13: } Chris@13: ```