123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- --TEST--
- Bug #65328 (Segfault when getting SplStack object Value)
- --FILE--
- <?php
- /**
- * @author AlexanderC
- */
- class Tree
- {
- /**
- * @var Node
- */
- protected $head;
- public function __construct(Node $head = null)
- {
- $this->head = $head ? : new Node('HEAD');
- }
- /**
- * @return Node
- */
- public function getHead()
- {
- return $this->head;
- }
- /**
- * @param mixed $uid
- * @return Node|bool
- */
- public function find($uid)
- {
- $iterator = $this->getIterator();
- /** @var Node $node */
- foreach($iterator as $node) {
- if($node->getUid() === $uid) {
- return $node;
- }
- }
- return false;
- }
- /**
- * @param mixed $uid
- * @return \SplStack
- */
- public function & findAll($uid)
- {
- $result = new \SplStack();
- /** @var Node $node */
- foreach($this->getIterator() as $node) {
- if($node->getUid() == $uid) {
- $result->push($node);
- }
- }
- return $result;
- }
- /**
- * @return \RecursiveIteratorIterator
- */
- public function getIterator(): Traversable
- {
- return new \RecursiveIteratorIterator(
- $this->head->getChildren(),
- \RecursiveIteratorIterator::SELF_FIRST
- );
- }
- }
- class Node extends \RecursiveArrayIterator implements \Countable
- {
- /**
- * @var array
- */
- protected $children = [];
- /**
- * @var Node
- */
- protected $parent;
- /**
- * @var mixed
- */
- protected $data;
- /**
- * @var mixed
- */
- protected $uid;
- /**
- * @var int
- */
- protected $index = 0;
- /**
- * @var bool
- */
- protected $assureUnique;
- /**
- * @param mixed $data
- * @param mixed $uid
- * @param Node $parent
- * @param bool $assureUnique
- */
- public function __construct($data, $uid = null, Node $parent = null, $assureUnique = false)
- {
- if(null !== $parent) {
- $this->parent = $parent;
- }
- $this->data = $data;
- $this->uid = $uid ? : uniqid(sha1(serialize($data)), true);
- $this->assureUnique = $assureUnique;
- }
- /**
- * @param mixed $uid
- */
- public function setUid($uid)
- {
- $this->uid = $uid;
- }
- /**
- * @return mixed
- */
- public function getUid()
- {
- return $this->uid;
- }
- /**
- * @param Node $child
- */
- public function addChild(Node $child)
- {
- $child->setParent($this);
- $this->children[] = $child;
- }
- /**
- * @param array $children
- */
- public function setChildren(array $children)
- {
- $this->children = $children;
- }
- /**
- * @return array
- */
- public function getChildrenArray()
- {
- return $this->children;
- }
- /**
- * @param mixed $data
- */
- public function setData($data)
- {
- $this->data = $data;
- }
- /**
- * @return mixed
- */
- public function getData()
- {
- return $this->data;
- }
- /**
- * @param Node $parent
- * @throws \RuntimeException
- */
- public function setParent(Node $parent)
- {
- if(true === $this->assureUnique && !self::checkUnique($parent, $this->uid)) {
- throw new \RuntimeException("Node uid is not unique in assigned node tree");
- }
- $this->parent = $parent;
- }
- /**
- * @param Node $node
- * @param mixed $uid
- * @return bool
- */
- protected static function checkUnique(Node $node, $uid)
- {
- $headNode = $node;
- do {
- $headNode = $node;
- } while($node = $node->getParent());
- $tree = new Tree($headNode);
- return !$tree->find($uid);
- }
- /**
- * @return \IJsonRPC\Helpers\Tree\Node
- */
- public function getParent()
- {
- return $this->parent;
- }
- public function current(): Node
- {
- return $this->children[$this->index];
- }
- /**
- * @return scalar
- */
- public function key(): string|int|null
- {
- return $this->index;
- }
- public function next(): void
- {
- ++$this->index;
- }
- public function rewind(): void
- {
- $this->index = 0;
- }
- public function valid(): bool
- {
- return array_key_exists($this->index, $this->children);
- }
- public function count(): int
- {
- return count($this->children);
- }
- public function hasChildren(): bool
- {
- return !empty($this->children);
- }
- public function getChildren(): RecursiveArrayIterator
- {
- return new \RecursiveArrayIterator($this->children);
- }
- }
- $tree = new Tree();
- $node1 = new Node('value1', 1);
- $tree->getHead()->addChild($node1);
- $node2 = new Node('value2', 2);
- $node1->addChild($node2);
- print_r($tree->findAll(2)->offsetGet(0));
- ?>
- --EXPECTF--
- Node Object
- (
- [children:protected] => Array
- (
- )
- [parent:protected] => Node Object
- (
- [children:protected] => Array
- (
- [0] => Node Object
- *RECURSION*
- )
- [parent:protected] => Node Object
- (
- [children:protected] => Array
- (
- [0] => Node Object
- *RECURSION*
- )
- [parent:protected] =>
- [data:protected] => HEAD
- [uid:protected] => %s
- [index:protected] => 0
- [assureUnique:protected] =>
- [storage:ArrayIterator:private] => Array
- (
- )
- )
- [data:protected] => value1
- [uid:protected] => 1
- [index:protected] => 1
- [assureUnique:protected] =>
- [storage:ArrayIterator:private] => Array
- (
- )
- )
- [data:protected] => value2
- [uid:protected] => 2
- [index:protected] => 0
- [assureUnique:protected] =>
- [storage:ArrayIterator:private] => Array
- (
- )
- )
|