12
12
use UnexpectedValueException ;
13
13
14
14
/**
15
- * A map of enumerators (EnumMap<T>) and mixed values .
15
+ * A map of enumerators and data values (EnumMap<K extends Enum, V>) .
16
16
*
17
17
* @copyright 2019 Marc Bennewitz
18
18
* @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
@@ -27,17 +27,18 @@ class EnumMap implements ArrayAccess, Countable, IteratorAggregate
27
27
private $ enumeration ;
28
28
29
29
/**
30
- * Internal map of ordinal number and value
30
+ * Internal map of ordinal number and data value
31
31
* @var array
32
32
*/
33
33
private $ map = [];
34
34
35
35
/**
36
36
* Constructor
37
37
* @param string $enumeration The classname of the enumeration type
38
+ * @param null|iterable $map Initialize map
38
39
* @throws InvalidArgumentException
39
40
*/
40
- public function __construct (string $ enumeration )
41
+ public function __construct (string $ enumeration, iterable $ map = null )
41
42
{
42
43
if (!\is_subclass_of ($ enumeration , Enum::class)) {
43
44
throw new InvalidArgumentException (\sprintf (
@@ -47,10 +48,129 @@ public function __construct(string $enumeration)
47
48
));
48
49
}
49
50
$ this ->enumeration = $ enumeration ;
51
+
52
+ if ($ map ) {
53
+ $ this ->addIterable ($ map );
54
+ }
55
+ }
56
+
57
+ /* write access (mutable) */
58
+
59
+ /**
60
+ * Adds the given enumerator (object or value) mapping to the specified data value.
61
+ * @param Enum|null|bool|int|float|string|array $enumerator
62
+ * @param mixed $value
63
+ * @throws InvalidArgumentException On an invalid given enumerator
64
+ * @see offsetSet()
65
+ */
66
+ public function add ($ enumerator , $ value ): void
67
+ {
68
+ $ ord = ($ this ->enumeration )::get ($ enumerator )->getOrdinal ();
69
+ $ this ->map [$ ord ] = $ value ;
50
70
}
51
71
52
72
/**
53
- * Get the classname of the enumeration
73
+ * Adds the given iterable, mapping enumerators (objects or values) to data values.
74
+ * @param iterable $map
75
+ * @throws InvalidArgumentException On an invalid given enumerator
76
+ */
77
+ public function addIterable (iterable $ map ): void
78
+ {
79
+ $ innerMap = $ this ->map ;
80
+ foreach ($ map as $ enumerator => $ value ) {
81
+ $ ord = ($ this ->enumeration )::get ($ enumerator )->getOrdinal ();
82
+ $ innerMap [$ ord ] = $ value ;
83
+ }
84
+ $ this ->map = $ innerMap ;
85
+ }
86
+
87
+ /**
88
+ * Removes the given enumerator (object or value) mapping.
89
+ * @param Enum|null|bool|int|float|string|array $enumerator
90
+ * @throws InvalidArgumentException On an invalid given enumerator
91
+ * @see offsetUnset()
92
+ */
93
+ public function remove ($ enumerator ): void
94
+ {
95
+ $ ord = ($ this ->enumeration )::get ($ enumerator )->getOrdinal ();
96
+ unset($ this ->map [$ ord ]);
97
+ }
98
+
99
+ /**
100
+ * Removes the given iterable enumerator (object or value) mappings.
101
+ * @param iterable $enumerators
102
+ * @throws InvalidArgumentException On an invalid given enumerator
103
+ */
104
+ public function removeIterable (iterable $ enumerators ): void
105
+ {
106
+ $ map = $ this ->map ;
107
+ foreach ($ enumerators as $ enumerator ) {
108
+ $ ord = ($ this ->enumeration )::get ($ enumerator )->getOrdinal ();
109
+ unset($ map [$ ord ]);
110
+ }
111
+
112
+ $ this ->map = $ map ;
113
+ }
114
+
115
+ /* write access (immutable) */
116
+
117
+ /**
118
+ * Creates a new map with the given enumerator (object or value) mapping to the specified data value added.
119
+ * @param Enum|null|bool|int|float|string|array $enumerator
120
+ * @param mixed $value
121
+ * @return static
122
+ * @throws InvalidArgumentException On an invalid given enumerator
123
+ */
124
+ public function with ($ enumerator , $ value ): self
125
+ {
126
+ $ clone = clone $ this ;
127
+ $ clone ->add ($ enumerator , $ value );
128
+ return $ clone ;
129
+ }
130
+
131
+ /**
132
+ * Creates a new map with the given iterable mapping enumerators (objects or values) to data values added.
133
+ * @param iterable $map
134
+ * @return static
135
+ * @throws InvalidArgumentException On an invalid given enumerator
136
+ */
137
+ public function withIterable (iterable $ map ): self
138
+ {
139
+ $ clone = clone $ this ;
140
+ $ clone ->addIterable ($ map );
141
+ return $ clone ;
142
+ }
143
+
144
+ /**
145
+ * Create a new map with the given enumerator mapping removed.
146
+ * @param Enum|null|bool|int|float|string|array $enumerator
147
+ * @return static
148
+ * @throws InvalidArgumentException On an invalid given enumerator
149
+ */
150
+ public function without ($ enumerator ): self
151
+ {
152
+ $ clone = clone $ this ;
153
+ $ clone ->remove ($ enumerator );
154
+ return $ clone ;
155
+ }
156
+
157
+ /**
158
+ * Creates a new map with the given iterable enumerator (object or value) mappings removed.
159
+ * @param iterable $enumerators
160
+ * @return static
161
+ * @throws InvalidArgumentException On an invalid given enumerator
162
+ */
163
+ public function withoutIterable (iterable $ enumerators ): self
164
+ {
165
+ $ clone = clone $ this ;
166
+ $ clone ->removeIterable ($ enumerators );
167
+ return $ clone ;
168
+ }
169
+
170
+ /* read access */
171
+
172
+ /**
173
+ * Get the classname of the enumeration type.
54
174
* @return string
55
175
*/
56
176
public function getEnumeration (): string
@@ -59,7 +179,29 @@ public function getEnumeration(): string
59
179
}
60
180
61
181
/**
62
- * Get a list of map keys
182
+ * Get the mapped data value of the given enumerator (object or value).
183
+ * @param Enum|null|bool|int|float|string|array $enumerator
184
+ * @return mixed
185
+ * @throws InvalidArgumentException On an invalid given enumerator
186
+ * @throws UnexpectedValueException If the given enumerator does not exist in this map
187
+ * @see offsetGet()
188
+ */
189
+ public function get ($ enumerator )
190
+ {
191
+ $ enumerator = ($ this ->enumeration )::get ($ enumerator );
192
+ $ ord = $ enumerator ->getOrdinal ();
193
+ if (!\array_key_exists ($ ord , $ this ->map )) {
194
+ throw new UnexpectedValueException (sprintf (
195
+ 'Enumerator %s could not be found ' ,
196
+ \var_export ($ enumerator ->getValue (), true )
197
+ ));
198
+ }
199
+
200
+ return $ this ->map [$ ord ];
201
+ }
202
+
203
+ /**
204
+ * Get a list of enumerator keys.
63
205
* @return Enum[]
64
206
*/
65
207
public function getKeys (): array
@@ -68,7 +210,7 @@ public function getKeys(): array
68
210
}
69
211
70
212
/**
71
- * Get a list of map values
213
+ * Get a list of mapped data values.
72
214
* @return mixed[]
73
215
*/
74
216
public function getValues (): array
@@ -77,10 +219,10 @@ public function getValues(): array
77
219
}
78
220
79
221
/**
80
- * Search for the given value
222
+ * Search for the given data value.
81
223
* @param mixed $value
82
224
* @param bool $strict Use strict type comparison
83
- * @return Enum|null The found key or NULL
225
+ * @return Enum|null The enumerator object of the first matching data value or NULL
84
226
*/
85
227
public function search ($ value , bool $ strict = false )
86
228
{
@@ -93,7 +235,7 @@ public function search($value, bool $strict = false)
93
235
}
94
236
95
237
/**
96
- * Test if the given enumerator exists
238
+ * Test if the given enumerator key (object or value) exists.
97
239
* @param Enum|null|bool|int|float|string|array $enumerator
98
240
* @return bool
99
241
* @see offsetExists
@@ -109,8 +251,10 @@ public function contains($enumerator): bool
109
251
}
110
252
}
111
253
254
+ /* ArrayAccess */
255
+
112
256
/**
113
- * Test if the given enumerator key exists and is not NULL
257
+ * Test if the given enumerator key (object or value) exists and is not NULL
114
258
* @param Enum|null|bool|int|float|string|array $enumerator
115
259
* @return bool
116
260
* @see contains
@@ -126,57 +270,52 @@ public function offsetExists($enumerator): bool
126
270
}
127
271
128
272
/**
129
- * Get mapped data for the given enumerator
273
+ * Get the mapped data value of the given enumerator (object or value).
130
274
* @param Enum|null|bool|int|float|string|array $enumerator
131
- * @return mixed
275
+ * @return mixed The mapped date value of the given enumerator or NULL
132
276
* @throws InvalidArgumentException On an invalid given enumerator
133
- * @throws UnexpectedValueException If the given enumerator does not exist in this map
277
+ * @see get()
134
278
*/
135
279
public function offsetGet ($ enumerator )
136
280
{
137
- $ enumerator = ($ this ->enumeration )::get ($ enumerator );
138
- $ ord = $ enumerator ->getOrdinal ();
139
- if (!isset ($ this ->map [$ ord ]) && !\array_key_exists ($ ord , $ this ->map )) {
140
- throw new UnexpectedValueException (sprintf (
141
- 'Enumerator %s could not be found ' ,
142
- \var_export ($ enumerator ->getValue (), true )
143
- ));
281
+ try {
282
+ return $ this ->get ($ enumerator );
283
+ } catch (UnexpectedValueException $ e ) {
284
+ return null ;
144
285
}
145
-
146
- return $ this ->map [$ ord ];
147
286
}
148
287
149
288
/**
150
- * Attach a new enumerator or overwrite an existing one
289
+ * Adds the given enumerator (object or value) mapping to the specified data value.
151
290
* @param Enum|null|bool|int|float|string|array $enumerator
152
291
* @param mixed $value
153
292
* @return void
154
293
* @throws InvalidArgumentException On an invalid given enumerator
155
- * @see attach ()
294
+ * @see add ()
156
295
*/
157
296
public function offsetSet ($ enumerator , $ value = null ): void
158
297
{
159
- $ ord = ($ this ->enumeration )::get ($ enumerator )->getOrdinal ();
160
- $ this ->map [$ ord ] = $ value ;
298
+ $ this ->add ($ enumerator , $ value );
161
299
}
162
300
163
301
/**
164
- * Detach an existing enumerator
302
+ * Removes the given enumerator (object or value) mapping.
165
303
* @param Enum|null|bool|int|float|string|array $enumerator
166
304
* @return void
167
305
* @throws InvalidArgumentException On an invalid given enumerator
168
- * @see detach ()
306
+ * @see remove ()
169
307
*/
170
308
public function offsetUnset ($ enumerator ): void
171
309
{
172
- $ ord = ($ this ->enumeration )::get ($ enumerator )->getOrdinal ();
173
- unset($ this ->map [$ ord ]);
310
+ $ this ->remove ($ enumerator );
174
311
}
175
312
313
+ /* IteratorAggregate */
314
+
176
315
/**
177
316
* Get a new Iterator.
178
317
*
179
- * @return Iterator
318
+ * @return Iterator Iterator<K extends Enum, V>
180
319
*/
181
320
public function getIterator (): Iterator
182
321
{
@@ -186,6 +325,8 @@ public function getIterator(): Iterator
186
325
}
187
326
}
188
327
328
+ /* Countable */
329
+
189
330
/**
190
331
* Count the number of elements
191
332
*
0 commit comments