Skip to content

Commit 6ecc9cd

Browse files
author
fureev
committed
feat: add HashCollection
1 parent f6066f8 commit 6ecc9cd

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Php\Support\Structures\Collections;
6+
7+
use ArrayAccess;
8+
use Closure;
9+
use Countable;
10+
11+
use function array_key_exists;
12+
use function count;
13+
use function in_array;
14+
15+
/**
16+
* @template T
17+
*/
18+
class HashCollection implements ArrayAccess, Countable
19+
{
20+
/**
21+
* @param array<string, T> $elements
22+
*/
23+
public function __construct(protected array $elements = [])
24+
{
25+
}
26+
27+
/**
28+
* Gets a native PHP array of the elements.
29+
*
30+
* @return array<string, T>
31+
*/
32+
public function all(): array
33+
{
34+
return $this->elements;
35+
}
36+
37+
/**
38+
* Checks whether the collection contains an element with the specified key/index.
39+
*
40+
* @param string $key The key/index to check for.
41+
*
42+
* @return bool TRUE if the collection contains an element with the specified key/index,
43+
* FALSE otherwise.
44+
*/
45+
public function hasKey(string $key): bool
46+
{
47+
return isset($this->elements[$key]) || array_key_exists($key, $this->elements);
48+
}
49+
50+
/**
51+
* Gets the element at the specified key/index.
52+
*
53+
* @param string $key The key/index of the element to retrieve.
54+
*
55+
* @return T|null
56+
*/
57+
public function get(string $key): mixed
58+
{
59+
return $this->elements[$key] ?? null;
60+
}
61+
62+
63+
/**
64+
* Sets an element in the collection at the specified key/index.
65+
*
66+
* @param string $key The key/index of the element to set.
67+
* @param T $value The element to set.
68+
*/
69+
public function set(string $key, mixed $value): void
70+
{
71+
$this->elements[$key] = $value;
72+
}
73+
74+
75+
/**
76+
* Adds an element at the end of the collection.
77+
*
78+
* @param T $element The element to add.
79+
*/
80+
public function add(object $element): bool
81+
{
82+
$this->elements[$element::class] = $element;
83+
84+
return true;
85+
}
86+
87+
/**
88+
* Removes the element at the specified index from the collection.
89+
*
90+
* @param string $key The key/index of the element to remove.
91+
*
92+
* @return T|null The removed element or NULL, if the collection did not contain the element.
93+
*/
94+
public function remove(string $key): mixed
95+
{
96+
if (!isset($this->elements[$key]) && !array_key_exists($key, $this->elements)) {
97+
return null;
98+
}
99+
100+
$removed = $this->elements[$key];
101+
unset($this->elements[$key]);
102+
103+
return $removed;
104+
}
105+
106+
/**
107+
* @return int<0, max>
108+
*/
109+
public function count(): int
110+
{
111+
return count($this->elements);
112+
}
113+
114+
/**
115+
* @param string $offset
116+
*/
117+
public function offsetExists(mixed $offset): bool
118+
{
119+
return $this->hasKey($offset);
120+
}
121+
122+
/**
123+
* @param string $offset
124+
*
125+
* @return T|null
126+
*/
127+
public function offsetGet(mixed $offset): mixed
128+
{
129+
return $this->get($offset);
130+
}
131+
132+
/**
133+
* @param string|null $offset
134+
* @param T $value
135+
*/
136+
public function offsetSet(mixed $offset, mixed $value): void
137+
{
138+
if (!isset($offset)) {
139+
$this->add($value);
140+
141+
return;
142+
}
143+
144+
$this->set($offset, $value);
145+
}
146+
147+
/**
148+
* @param string $offset
149+
*/
150+
public function offsetUnset(mixed $offset): void
151+
{
152+
$this->remove($offset);
153+
}
154+
155+
/**
156+
* Checks whether the collection is empty (contains no elements).
157+
*/
158+
public function isEmpty(): bool
159+
{
160+
return empty($this->elements);
161+
}
162+
163+
/**
164+
* Checks whether an element is contained in the collection.
165+
* This is an O(n) operation, where n is the size of the collection.
166+
*
167+
* @param TMaybeContained $element The element to search for.
168+
*
169+
* @return bool TRUE if the collection contains the element, FALSE otherwise.
170+
* @phpstan-return (TMaybeContained is T ? bool : false)
171+
*
172+
* @template TMaybeContained
173+
*/
174+
public function contains(mixed $element): bool
175+
{
176+
return in_array($element, $this->elements, true);
177+
}
178+
179+
/**
180+
* Clears the collection, removing all elements.
181+
*/
182+
public function clear(): void
183+
{
184+
$this->elements = [];
185+
}
186+
187+
/**
188+
* Returns the first element of this collection that satisfies the predicate $func.
189+
*
190+
* @param Closure(string, T):bool $func The predicate.
191+
*
192+
* @return null|T The first element respecting the predicate, null if no element respects the predicate.
193+
*/
194+
public function find(Closure $func): mixed
195+
{
196+
return array_find($this->elements, fn($element, $key) => $func($key, $element));
197+
}
198+
}

0 commit comments

Comments
 (0)