public static function traverse(Digraph $graph, DepthFirstVisitorInterface $visitor, $start = NULL)
{
if ($start === NULL) {
$queue = self::find_sources($graph, $visitor);
} else {
if ($start instanceof \SplDoublyLinkedList) {
$queue = $start;
} else {
if (is_object($start)) {
$queue = new \SplDoublyLinkedList();
$queue->push($start);
}
}
}
if ($queue->isEmpty()) {
throw new RuntimeException('No start vertex or vertices were provided, and no source vertices could be found in the provided graph.', E_WARNING);
}
$visiting = new \SplObjectStorage();
$visited = new \SplObjectStorage();
$visitor->beginTraversal();
$visit = function ($vertex) use($graph, $visitor, &$visit, $visiting, $visited) {
if ($visiting->contains($vertex)) {
$visitor->onBackEdge($vertex, $visit);
} else {
if (!$visited->contains($vertex)) {
$visiting->attach($vertex);
$visitor->onStartVertex($vertex, $visit);
foreach ($graph->successorsOf($vertex) as $head) {
$visitor->onExamineEdge($vertex, $head, $visit);
$visit($head);
}
$visitor->onFinishVertex($vertex, $visit);
$visiting->detach($vertex);
$visited->attach($vertex);
}
}
};
// TODO experiment with adding a generator-producing visitor method that yields the queue here
while (!$queue->isEmpty()) {
$vertex = $queue->shift();
$visit($vertex);
}
$visitor->endTraversal();
}