PHP Puking on recursive object :(
Posted: Tue Nov 28, 2006 7:34 am
I'm working with a tree structure of objects which are all a subclass of the same base class.
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?
Simplified....
(I think it's the composite pattern, but recursive?)
At one point in NodeTree I need to switch the reference for $this->fooNodes["___location"] *if it's currently $this*. The problem is that because I have a reference to $this inside the class itself it won't allow me to make that comparison and throws an error that the recursion is too deep. Anybody got any better ideas?
Basically, PHP is choking on this situation:
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";