I have trees like this one:
$tree = array("A", array(
array("B", 1),
array("C", 2),
array("D",
array("E",
array("F")),
array("G")),
array("H", 3)));
Each node is an array, type of node is its first element and other elements are node's arguments (they can be list of other nodes, single node, some value etc.; node can have no argument, one argument or more arguments).
What do you think is the most elegant way to walk these type of trees?
I came up with two possibilities:
1) using switch
statement
/*
* + shorter
* + fall-througs (easy way to handle more nodes with same code)
*
* - worse readability
*/
function my_tree_walker($tree)
{
switch ($tree[0]) {
case 'A':
list($_, $subnodes) = $tree;
$ret = '';
foreach ($subnodes as $subnode) {
$ret .= my_tree_walker($subnode);
}
return $ret;
break;
case 'B': /*...*/ break;
case 'C': /*...*/ break;
case 'D': /*...*/ break;
case 'E': /*...*/ break;
case 'F': /*...*/ break;
case 'G': /*...*/ break;
case 'H': /*...*/ break;
}
}
2) object with method for each node type
/*
* + better readability
* + more declarative
*
* - longer
* - `new static` is PHP >=5.3 only
*/
abstract class TreeWalker
{
protected function __construct(){}
final protected function walk($node)
{
$nodetype = array_shift($node);
return call_user_func_array(array($this, 'walk' . $nodetype), $node);
}
public static function w($tree)
{
$instance = new static;
return $instance->walk($tree);
}
}
final class MyTreeWalker extends TreeWalker
{
protected function __construct()
{
// initialize
}
private function walkA($subnodes)
{
$ret = '';
foreach ($subnodes as $subnode) {
$ret .= $this->walk($subnode);
}
return $ret;
}
private function walkB($n) { /*...*/ }
private function walkC($n) { /*...*/ }
private function walkD($subnode) { /*...*/ }
private function walkE() { /*...*/ }
private function walkF() { /*...*/ }
private function walkG() { /*...*/ }
private function walkH($n) { /*...*/ }
}
Or do you suggest even more elegant way of walking trees?
I also considered nodes being objects and instead of separate tree walkers each node would have methods for walks inside. However I think it will make code harder to maintain, because parts of walkers' code will be placed in different locations and it will be harder to use same code for more nodes.