Because it's a tree, it has nodes. I need to track the locations of certain nodes so I group information about them (their ID's) into respective containers. I also keep a reference to the node they are stored in here. It's tricky to explain so let's just look at the code eh?
(I think it's the composite pattern, but recursive?)
Code: Select all
<?php
/**
* Each type of node must extend Node
*/
abstract class Node
{
// ... SNIP ....
protected $children = array();
/**
* Nest a child node in this document
* @param Node
* @param string The identifier to use, optional
* @param int Add the node before (-1) or after (+1) the other nodes
* @return string The identifier for this node
*/
public function addChild(Node $node, $id=null, $after=1)
{
if (empty($id))
{
do
{
$id = uniqid();
} while (array_key_exists($id, $this->children));
}
$id = (string) $id;
if ($after == -1) $this->children = array_merge(array($id => $node), $this->children);
else $this->children[$id] = $node;
return $id;
}
/**
* Check if a child exists identified by $id
* @param string Identifier to look for
* @return boolean
*/
public function hasChild($id)
{
return array_key_exists($id, $this->children);
}
/**
* Get a child node, identified by $id
* @param string The identifier for this child
* @return Node The child node
* @throws NodeException If no such child exists
*/
public function getChild($id)
{
if ($this->hasChild($id))
{
return $this->children[$id];
}
else throw new NodeException(
"Cannot retrieve child node identified by '" . $id . "' as it does not exist. Consider using hasChild() to check.");
}
/**
* Remove a node from the document
* @param string The identifier of the child
* @throws NodeException If no such part exists
*/
public function removeChild($id)
{
$id = (string) $id;
if (!$this->hasChild($id)) throw new NodeException(
"Cannot remove child part identified by '" . $id . "' as it does not exist. Consider using hasChild() to check.");
else
{
$this->children[$id] = null;
unset($this->children[$id]);
}
}
// .... SNIP ....
}Code: Select all
<?php
class FooNode extends Node
{
//some specific stuff here
}
class BarNode extends Node
{
//more specifics
}Code: Select all
<?php
class NodeTree extends Node
{
protected $fooNodes = array();
protected $barNodes = array();
public function __construct()
{
$this->fooNodes["___location"] =& $this; //Where Nodes of Type FooNode are found
$this->barNodes["___location"] =& $this; //Where nodes of type BarNode are found
}
public function attachBranch(Node $node)
{
//Add nodes to the relevant branch
switch (get_class($node))
{
case "FooNode":
$id = $this->fooNodes["___location"]->addChild($node);
$this->fooNodes[$id] = $id;
break;
case "BarNode": default:
$id = $this->barNodes["___location"]->addChild($node);
$this->barNodes[$id] = $id;
break;
}
}
}Basically, PHP is choking on this situation:
Code: Select all
<?php
class MyClass
{
protected $ref = null;
public function __construct()
{
$this->setRef($this);
}
public function setRef($obj)
{
$this->ref =& $this;
}
public function refIsMine()
{
return ($this->ref == $this);
}
}
$obj = new MyClass();
//Error that recursion is too deep
if ($obj->refIsMine()) echo "Reference not yet changed";