Visitors
To walk the whole graph of an already-parsed type, use the TypeLang\Parser\Traverser class. It accepts one or more TypeLang\Parser\Traverser\VisitorInterface implementations and calls each of them for every node it visits.
Let's write a visitor that prints the class name of every node it enters, using the convenience TypeLang\Parser\Traverser\Visitor abstract class (which no-ops every lifecycle method, so you only override what you need):
The Visitor Lifecycle
VisitorInterface (and its Visitor no-op base class) has four methods, called in this order for a single traverse() call:
Method | Called |
|---|---|
| once, before the first node is visited |
| once per node, on the way down, before its children |
| once per node, on the way back up, after its children |
| once, after the last node has been visited |
enter() may return TypeLang\Parser\Traverser\Command::SkipChildren to prevent the traverser from descending into that node's children — leave() is still called for the node itself, just not for anything beneath it.
Traverser API
new Traverser(iterable $visitors = [])— construct directly from a list of visitors, or use the equivalent staticTraverser::new($visitors).Traverser::through(VisitorInterface $visitor, iterable $nodes)— shortcut for the common "one visitor, traverse once, give it back to me" pattern — wraps the visitor in a new traverser, runs it, and returns the same visitor instance so you can immediately read state off it:// Find & collect all "Name" nodes $find = Traverser::through(new ClassNameMatcherVisitor(Name::class), [ $type ]);->with(VisitorInterface $visitor, bool $prepend = false)— returns a new traverser with an additional visitor appended (or prepended).->withPropertyAccessor(PropertyAccessorInterface $propertyAccessor)— returns a new traverser that discovers a node's children through a customPropertyAccessorInterfaceinstead of the default reflection-based one — see below.
Custom Property Access
By default, the traverser discovers a node's children via Traverser\PropertyAccessor\SimplePropertyAccessor, which reflects over every non-static, non-hooked public and non-public property and descends into whichever ones hold a Node or an iterable of them. You can supply your own PropertyAccessorInterface implementation (e.g. to only look at a specific subset of properties, for performance or for a custom node hierarchy) via Traverser::withPropertyAccessor().
Built-in Visitors
- MatcherVisitor / ClassNameMatcherVisitor
Find the first node matching an arbitrary predicate, or matching a given class. See MatcherVisitor and ClassNameMatcherVisitor.
- DumperVisitor / StreamDumperVisitor / StringDumperVisitor
Render the whole tree as an indented, human-readable dump — to a stream or into a string. See DumperVisitor, StreamDumperVisitor, and StringDumperVisitor.
- TypeMapVisitor
Rewrite every
Nameoccurrence in a tree via a callback — the mechanism behind Name resolution. See TypeMapVisitor.