This component provides a Tree that can be traversed and modified.
The Tree receives a root Node and contains methods to traverse the
nodes contained in the root node:
visitPostOrderTraverses its children first (left to right) and then itself.visitInOrderTraverses its left children first, then itself, and then its right children.visitPreOrderTraverses itself first, and then it's children (left to right).visitLevelOrderTraverses per level.
The tree implements the Visitor pattern. A number of common visitors are included in this component:
ValueVisitorreturns an array containing the value of each node.SerializerVisitorreturns a serialized representation of the tree.
There are also 2 abstract visitors that provide a base implementation:
Visitorimplements emptybeforeVisiting()andafterVisiting()methods.ArrayVisitorkeeps a record of the result for every visit that can be read by callinggetResult(): iterableafter the visitor is done.
To create your own visitor you need to let it implement VisitorInterface or extend the abstract Visitor or
ArrayVisitor class.
Sometimes you need to perform some action before the visitor starts visiting or after it is done visiting. For
these situations you can use beforeVisiting() and afterVisiting() methods. E.g. The ArrayVisitor always resets the
internal array on beforeVisiting() to prevent result stacking on multiple calls.
<?php
use Iwink\Tree\Node\Node;
use Iwink\Tree\Tree;
use Iwink\Tree\Visitor\ValueVisitor;
$nodes = [];
foreach (range('A', 'I') as $value) {
$nodes[$value] = new Node($value);
}
$nodes['D']->addChild($nodes['C'], $nodes['E']);
$nodes['H']->addChild($nodes['G'], $nodes['I'], $nodes['J']);
$nodes['B']->addChild($nodes['A'], $nodes['D']);
$nodes['F']->addChild($nodes['B'], $nodes['H']);
$tree = new Tree($nodes['F']);A visual representation of this tree looks like this:
F
/ \
B H
/ \ / | \
A D G I J
/ \
C ENow we can traverse this tree and apply a visitor:
// See code block above
$visitor = new ValueVisitor('strtolower'); // Convert the node's value to lowercase
$tree->visitPreOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['f', 'b', 'a', 'd', 'c', 'e', 'h', 'g', 'i', 'j']
$tree->visitInOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' 'j']
$tree->visitPostOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['a', 'c', 'e', 'd', 'b', 'g', 'i', 'j', 'h', 'f']
$tree->visitLevelOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['f', 'b', 'h', 'a', 'd', 'g', 'i', 'j', 'c', 'e']To persist the tree to a file or a database record, you can use TreeInterface::serialize(?callable $converter = null).
This serializes the tree to a format that preserves hierarchy and can be restored. If the node's values aren't scalar,
you might want to pass a $converter to this method so those values are serializable as well.
If you have a serialized tree, you can restore it using
TreeInterface::fromSerialized(array $serialized, ?callable $converter = null, string $node_class = Node::class). It
takes an optional $converter to restore the node's value if this isn't a scalar value. You can also pass your own
implementation of a $node_class to create a tree that consists of different nodes. Just make sure your node class
implements NodeInterface.
