*/ class GraphNode { /** * Parent of this node. * @var GraphNode */ protected $parent; /** * Value of this node. * @var mixed */ protected $value; /** * Children of this node. * @var GraphNode[] */ protected $children; /** * Create a new graph node. * * @param mixed $value */ public function __construct($value = null) { $this->value = $value; $this->children = []; } /** * Set the value of this node. * * @param mixed $value * @return void */ public function setValue($value): void { $this->value = $value; } /** * Get the value of this node. * * @return mixed */ public function getValue() { return $this->value; } /** * Set the parent node of this node. * * @param GraphNode $node * @return void */ public function setParent(GraphNode $node): void { $this->parent = $node; } /** * Determine whether this node has a parent. * * @return bool */ public function hasParent(): bool { return isset($this->parent); } /** * Get this node's parent node. * * @return GraphNode */ public function getParent(): GraphNode { return $this->parent; } /** * Count how many child nodes this node has. * * @return int */ public function countChildren(): int { return sizeof($this->children); } /** * Determine whether this node has any children. * * @return bool */ public function hasChildren(): bool { return sizeof($this->children) > 0; } /** * Fetch all of this node's children. * * @return GraphNode[] */ public function getChildren(): array { return $this->children; } /** * Add a node to this child's list of children. * * @param GraphNode $child * @return void */ public function appendChild(GraphNode $child): void { $this->children[] = $child; $child->setParent($this); } /** * Replace a child node with another node. * * @param GraphNode $original * @param GraphNode $new * @return void */ public function replaceChild(GraphNode $original, GraphNode $new): void { for ($i = 0; $i < sizeof($this->children); $i++) { if ($this->children[$i] === $original) { $this->children[$i] = $new; $new->setParent($this); return; } } } /** * Remove all children of this node. * * @return void */ public function clearChildren(): void { $this->children = []; } /** * Add a child node by value. * * @param mixed $value value to add as a child * @return GraphNode the node created as a child */ public function add($value): GraphNode { $this->children[] = new GraphNode($value); end($this->children)->setParent($this); return end($this->children); } /** * Walk through this node and all children, calling callback on each node. * * Callback is called on a node's children before a node * * @param callable $callback callback(GraphNode $node): void * @return void */ public function walk(callable $callback) { static::walkNodes([$this], $callback); } /** * Internal function for recursively visiting all nodes. * * @param GraphNode[] $nodes * @param callable $callback * @return void */ protected static function walkNodes(array $nodes, callable $callback) { foreach ($nodes as $node) { if ($node->hasChildren()) { static::walkNodes($node->getChildren(), $callback); } $callback($node); } } }