Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bdalziel/1105139 to your computer and use it in GitHub Desktop.
Save bdalziel/1105139 to your computer and use it in GitHub Desktop.
Within an object implementing Iterator, be careful when using foreach($this as $foo) as opposed to foreach($this->items as $foo). If you're traversing a tree based on iteration in two directions through recursion, you can easily interfere with the interna
<?php
require_once 'SimpleIteratorNodeClasses.php';
class TryingToBeCleverNode extends SimpleNode {
public function getDepthOfDeepestChild () {
$max_depth = 'N/A';
//////////////////////////////////////////////////////////////////////
/// Hey, I'm iteratable! If I just use '$this', I'm good...!
/// ...but oh man, you could spend hours debugging this down the line
//////////////////////////////////////////////////////////////////////
foreach ($this as $key => $node) {
$node_depth = $node->getDepth();
$node_deepest_child_depth = $node->getDepthOfDeepestChild();
$max_depth = max((is_numeric($max_depth) ? $max_depth : 0),
$node_depth,
$node_deepest_child_depth);
}
return $max_depth;
}
}
class NotTryingToBeCleverNode extends SimpleNode {
public function getDepthOfDeepestChild () {
$max_depth = 'N/A';
//////////////////////////////////////////////////////////////////////
/// Hey, I'm iteratable! But i don't want to interfere with the
/// internal iteration pointer, I'll play it safe...
//////////////////////////////////////////////////////////////////////
foreach ($this->items as $key => $node) {
$node_depth = $node->getDepth();
$node_deepest_child_depth = $node->getDepthOfDeepestChild();
$max_depth = max((is_numeric($max_depth) ? $max_depth : 0),
$node_depth,
$node_deepest_child_depth);
}
return $max_depth;
}
}
//////////////////////////////////////////////////////////////////////
/// Tree structure:
/// |-------|
/// | A |
/// |---|---|
/// | B | C |
/// |-------|
//////////////////////////////////////////////////////////////////////
$trying_to_be_clever_node = new TryingToBeCleverNode('A');
$trying_to_be_clever_node->addNodes(array(new TryingToBeCleverNode('B'), new TryingToBeCleverNode('C')));
print "Trying to be clever node:\n";
print_level_leaf_data($trying_to_be_clever_node);
//////////////////////////////////////////////////////////////////////
/// Trying to be clever node:
/// Node 'A': Depth of deepest child '1', distance from max tree depth '1'
/// Node 'B': Depth of deepest child 'N/A', distance from max tree depth '0'
/// @brief WTF - why only the LHS dude?!
//////////////////////////////////////////////////////////////////////
$not_trying_to_be_clever_node = new NotTryingToBeCleverNode('A');
$not_trying_to_be_clever_node->addNodes(array(new NotTryingToBeCleverNode('B'), new NotTryingToBeCleverNode('C')));
print "Not trying to be clever node:\n";
print_level_leaf_data($not_trying_to_be_clever_node);
//////////////////////////////////////////////////////////////////////
/// Not trying to be clever node:
/// Node 'A': Depth of deepest child '1', distance from max tree depth '1'
/// Node 'B': Depth of deepest child 'N/A', distance from max tree depth '0'
/// Node 'C': Depth of deepest child 'N/A', distance from max tree depth '0'
/// @brief That's more like it
//////////////////////////////////////////////////////////////////////
function print_level_leaf_data ($node) {
print "Node '" . $node->getValue() . "': Depth of deepest child '" . $node->getDepthOfDeepestChild() ."', distance from max tree depth '" . $node->getDistanceFromTreeMaxDepth() . "'\n";
foreach ($node as $tree_node) {
print_level_leaf_data($tree_node);
}
}
?>
<?php
//////////////////////////////////////////////////////////////////////
/// Simple list. Supports iteration
/// Items can be added to the list via 'appendItem'.
//////////////////////////////////////////////////////////////////////
class SimpleList implements Iterator, Countable {
public function appendItem ($item) {
array_push($this->items, $item);
}
//////////////////////////////////////////////////////////////////////
/// Iterator interface implementation. Uses an array.
/// Adapted from http://php.net/manual/en/class.iterator.php
//////////////////////////////////////////////////////////////////////
protected $items = array();
private $position = 0;
public function rewind () {
$this->position = 0;
}
public function current () {
return $this->items[$this->position];
}
public function key () {
return $this->position;
}
public function next () {
++$this->position;
}
public function valid () {
return isset($this->items[$this->position]);
}
//////////////////////////////////////////////////////////////////////
/// Countable interface implementation
//////////////////////////////////////////////////////////////////////
public function count()
{
return count($this->items);
}
}
abstract class SimpleNode extends SimpleList
{
protected $value;
protected $parent_node;
public function __construct ($value) {
$this->value = $value;
}
//////////////////////////////////////////////////////////////////////
///
/// @param node
///
/// @return (bool) Whether or not the node was added to the
/// composite successfully. If false, most likely the node
/// is of an unsupported type
//////////////////////////////////////////////////////////////////////
public function addNode ($node) {
if ($node instanceof SimpleNode)
{
// has parent functionality
$node->setParent($this);
}
return parent::appendItem($node);
}
public function addNodes ($nodes) {
foreach ($nodes as $node) {
$this->addNode($node);
}
}
//////////////////////////////////////////////////////////////////////
/// Make sure the client does not manipulate the list directly, bypassing
/// node logic
//////////////////////////////////////////////////////////////////////
public function appendItem ($item) {
return $this->addNode($item);
}
public function getValue () {
return $this->value;
}
public function setParent ($node) {
$this->parent_node = $node;
}
public function getParent () {
return $this->parent_node;
}
public function hasParent () {
return (bool) $this->parent_node;
}
public function getDepth () {
if ($this->hasParent())
{
return (int) ($this->getParent()->getDepth() +1);
}
return 0;
}
public abstract function getDepthOfDeepestChild ();
public function getDistanceFromTreeMaxDepth () {
return $this->getDepthOfOwningTreeDeepestChild() - $this->getDepth();
}
protected function getDepthOfOwningTreeDeepestChild () {
if ($this->hasParent())
{
return $this->getParent()->getDepthOfOwningTreeDeepestChild();
}
return $this->getDepthOfDeepestChild();
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment