1: <?php declare(strict_types=1);
2:
3: namespace Salient\Iterator;
4:
5: use Iterator;
6: use OutOfRangeException;
7: use ReturnTypeWillChange;
8:
9: /**
10: * Iterates over arrays and objects
11: *
12: * @api
13: *
14: * @implements Iterator<array-key,mixed>
15: */
16: class GraphIterator implements Iterator
17: {
18: protected object $Object;
19: /** @var mixed[] */
20: protected array $Array;
21: protected bool $IsObject;
22: /** @var array-key[] */
23: protected array $Keys;
24:
25: /**
26: * @api
27: *
28: * @param mixed[]|object $value
29: */
30: public function __construct(&$value)
31: {
32: if (is_object($value)) {
33: $this->Object = $value;
34: $this->IsObject = true;
35: } else {
36: $this->Array = &$value;
37: $this->IsObject = false;
38: }
39: }
40:
41: /**
42: * @return mixed
43: * @disregard P1038
44: */
45: #[ReturnTypeWillChange]
46: public function current()
47: {
48: if (
49: !isset($this->Keys)
50: || ($key = current($this->Keys)) === false
51: ) {
52: throw new OutOfRangeException('Invalid position');
53: }
54: return $this->IsObject
55: ? $this->Object->{$key}
56: : $this->Array[$key];
57: }
58:
59: /**
60: * @return array-key|null
61: * @disregard P1038
62: */
63: #[ReturnTypeWillChange]
64: public function key()
65: {
66: return !isset($this->Keys)
67: || ($key = current($this->Keys)) === false
68: ? null
69: : $key;
70: }
71:
72: /**
73: * @inheritDoc
74: */
75: public function next(): void
76: {
77: if (isset($this->Keys)) {
78: next($this->Keys);
79: }
80: }
81:
82: /**
83: * @inheritDoc
84: */
85: public function rewind(): void
86: {
87: $this->Keys = $this->IsObject
88: ? array_keys(get_object_vars($this->Object))
89: : array_keys($this->Array);
90: reset($this->Keys);
91: }
92:
93: /**
94: * @inheritDoc
95: */
96: public function valid(): bool
97: {
98: return isset($this->Keys)
99: && current($this->Keys) !== false;
100: }
101: }
102: