initialList = $__initialList; $this->open = null; $this->closed = null; $this->nodes = []; $this->searchNodes = []; /** * Step 1. Create a Search graph */ if ($__build) { $this->build(); } } /** * @return Node * @throws Exception */ protected function popFirst(&$__list) { /** * Step 3. If OPEN is empty - throw error (we are actually done) */ if (sizeof($__list) === 0) { throw new Exception("Done"); } return array_splice($__list, 0, 1)[0]; } /** * @throws ErrorException */ protected function remove($__name, &$__list) { for ($i = 0; $i < sizeof($__list); $i++) { if ($__list[$i]->name === $__name) { return array_splice($__list, $i, 1)[0]; } } throw new ErrorException('Node not found in list : ' . $__name); } protected function removeAll($__parent, &$__list) { $nodes = []; for ($i = sizeof($__list) - 1; $i >= 0; $i--) { if ($__list[$i]->parent === $__parent) { array_push($nodes, array_splice($__list, $i, 1)[0]); } } return $nodes; } /** * Step 6. Expand $node by generating a set M of successors that are not already ancestors of * $node in G. Install them into G. */ protected function expand($node) { if ($node->name === 'R3') { $children = $this->removeAll(null, $this->initialList); } else { $children = $this->removeAll($node->name, $this->initialList); } return $children; } protected function linkToParent($node) { foreach ($node->children as $child) { $child->nameSpace = $node->nameSpace . $node->nameSpaceClassName . '.'; $child->parent = $node; } } protected function pushToList(&$__list, $__nodes) { foreach ($__nodes as $node) { array_push($__list, $node); } } /** * @throws Exception */ protected function processOpen($searchMode = false, $property = null, $value = null) { /** * Step 3. If OPEN is empty - throw Exception (we are actually done) */ $node = $this->popFirst($this->open); /** * Step 4. Select the first node on OPEN - move it to CLOSED */ array_push($this->closed, $node); // array_push($this->searchNodes, $node); /** * Step 5. If $node is a GOAL node - we are done - we skip this step for build because then we are done * only when $this->open is empty */ if ($searchMode) { if ($property === null) { throw new ErrorException('Search mode cannot be true without a property specified'); } if ($node->$property === $value) { return $node; } } /** * Step 6. Expand $node by generating a set M of successors that are not already ancestors of * $node in G. Install them into G. * * We skip 6. and 7. a) when in search mode, because we already have children linked to parents */ if (!$searchMode) { $successors = $this->expand($node); $node->children = $successors; /** * Step 7. a) Establish a link from each successor to its parent */ $this->linkToParent($node); } /** * Step 7. b) Add all successors to OPEN */ $this->pushToList($this->open, $node->children); /** * Step 8. We skip this because we do not do any re-ordering on the graph */ /** * Step 9. Go back to Step 3 */ return $this->processOpen($searchMode, $property, $value); } /** * @param $property * @param $value * @return Array | Node * @throws ErrorException */ public function search($property, $value) { if (sizeof($this->nodes) <= 0) { throw new ErrorException('This graph is not built yet'); } /** * Step 1. Create a Search graph containing only the start node - put it on a list called OPEN */ $startNode = $this->nodes[0]; $this->searchNodes = []; array_push($this->searchNodes, $startNode); $this->open = []; array_push($this->open, $startNode); /** * Step 2. Create a list called CLOSED initially empty */ $this->closed = []; try { /** * Step 3. If OPEN is empty - we could not find the node */ return $this->processOpen(true, $property, $value); } catch (Exception $e) { return $this->searchNodes; } } /** * @throws ErrorException */ protected function build() { if (sizeof($this->initialList) <= 0) { throw new ErrorException('Bad initial list'); } /** * Step 1. Create a Search graph containing only the start node - put it on a list called OPEN */ $startNode = $this->remove("R3", $this->initialList); array_push($this->nodes, $startNode); $this->open = []; array_push($this->open, $startNode); /** * Step 2. Create a list called CLOSED initially empty */ $this->closed = []; try { /** * Step 3. If OPEN is empty - throw Exception (we are actually done) */ return $this->processOpen(); } catch (Exception $e) { return $e->getMessage(); } } /** * @return [] */ public function walk() { try { $this->search('name', 'all'); return $this->closed; } catch (ErrorException $e) { return []; } } } class Node { public $file = ''; public $name = ''; public $nameSpace = ''; public $parent = null; public $children = null; function __construct( $__file, $__name, $__nameSpace = '', $__nameSpaceClassName = '', $__parent = null, $__children = null ) { $this->file = $__file; $this->name = $__name; $this->nameSpace = $__nameSpace; $this->nameSpaceClassName = $__nameSpaceClassName; $this->parent = $__parent; $this->children = $__children; } }