iwink / tree
Tree data structure for PHP
Installs: 43 916
Dependents: 0
Suggesters: 0
Security: 0
Stars: 3
Watchers: 4
Forks: 0
Open Issues: 0
pkg:composer/iwink/tree
Requires
- php: ^7.4|^8.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.6
README
This component provides a Tree that can be traversed and modified.
Tree
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.
Visitors
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.
Creating your own visitor
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.
Example
Building the tree
<?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 E
Traversing the tree
Now 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']
Serializing the tree
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.
Building the tree from a serialized format
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.