'G', 'F' => 'G', 'G' => 'D', 'E' => 'D', 'A' => 'E', 'B' => 'C', 'C' => 'E', 'D' => null); // add children to parents $flat = array(); # temporary array foreach ($tree as $name => $parent) { $flat[$name]['name'] = $name; # self if (NULL === $parent) { # no parent, is root element, assign it to $tree $tree = &$flat[$name]; } else { # has parent, add self as child $flat[$parent]['children'][] = &$flat[$name]; } } unset($flat); class TreeNode { protected $data; public function __construct(array $element) { if (!isset($element['name'])) throw new InvalidArgumentException('Element has no name.'); if (isset($element['children']) && !is_array($element['children'])) throw new InvalidArgumentException('Element has invalid children.'); $this->data = $element; } public function getName() { return $this->data['name']; } public function hasChildren() { return isset($this->data['children']) && count($this->data['children']); } /** * @return array of child TreeNode elements */ public function getChildren() { $children = $this->hasChildren() ? $this->data['children'] : array(); $class = 'TreeNode'; foreach($children as &$element) { $element = new $class($element); } unset($element); return $children; } } class TreeNodesIterator implements RecursiveIterator { private $nodes; public function __construct(array $nodes) { $this->nodes = new ArrayIterator($nodes); } public function getInnerIterator() { return $this->nodes; } public function getChildren() { return new TreeNodesIterator($this->nodes->current()->getChildren()); } public function hasChildren() { return $this->nodes->current()->hasChildren(); } public function rewind() { $this->nodes->rewind(); } public function valid() { return $this->nodes->valid(); } public function current() { return $this->nodes->current(); } public function key() { return $this->nodes->key(); } public function next() { return $this->nodes->next(); } } class RecursiveListIterator extends RecursiveIteratorIterator { private $elements; /** * @var ListDecorator */ private $decorator; public function addDecorator(ListDecorator $decorator) { $this->decorator = $decorator; } public function __construct($iterator, $mode = RecursiveIteratorIterator::SELF_FIRST, $flags = 0) { parent::__construct($iterator, $mode, $flags); } private function event($name) { // event debug code: printf("--- %'.-20s --- (Depth: %d, Element: %d)\n", $name, $this->getDepth(), @$this->elements[$this->getDepth()]); $callback = array($this->decorator, $name); is_callable($callback) && call_user_func($callback); } public function beginElement() { $this->event('beginElement'); } public function beginChildren() { $this->event('beginChildren'); } public function endChildren() { $this->testEndElement(); $this->event('endChildren'); } private function testEndElement($depthOffset = 0) { $depth = $this->getDepth() + $depthOffset; isset($this->elements[$depth]) || $this->elements[$depth] = 0; $this->elements[$depth] && $this->event('endElement'); } public function nextElement() { $this->testEndElement(); $this->event('{nextElement}'); $this->event('beginElement'); $this->elements[$this->getDepth()] = 1; } public function beginIteration() { $this->event('beginIteration'); } public function endIteration() { $this->testEndElement(); $this->event('endIteration'); } } class ListDecorator { private $iterator; public function __construct(RecursiveListIterator $iterator) { $this->iterator = $iterator; } public function inset($add = 0) { return str_repeat(' ', $this->iterator->getDepth()*2+$add); } public function beginElement() { printf("%s