2
2
3
3
namespace MabeEnum ;
4
4
5
- use SplObjectStorage ;
5
+ use ArrayAccess ;
6
+ use Countable ;
6
7
use InvalidArgumentException ;
8
+ use Iterator ;
9
+ use UnexpectedValueException ;
7
10
8
11
/**
9
- * A map of enumerator keys of the given enumeration (EnumMap<T>)
10
- * based on SplObjectStorage
12
+ * A map of enumerators (EnumMap<T>) and mixed values.
11
13
*
12
14
* @link http://github.com/marc-mabe/php-enum for the canonical source repository
13
15
* @copyright Copyright (c) 2017 Marc Bennewitz
14
16
* @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
15
17
*/
16
- class EnumMap extends SplObjectStorage
18
+ class EnumMap implements ArrayAccess, Countable, Iterator
17
19
{
18
20
/**
19
21
* The classname of the enumeration type
20
22
* @var string
21
23
*/
22
24
private $ enumeration ;
23
25
26
+ /**
27
+ * Internal map of ordinal number and value
28
+ * @var array
29
+ */
30
+ private $ map = [];
31
+
32
+ /**
33
+ * List of ordinal numbers
34
+ * @var int[]
35
+ */
36
+ private $ ordinals = [];
37
+
38
+ /**
39
+ * Current iterator position
40
+ * @var int
41
+ */
42
+ private $ pos = 0 ;
43
+
24
44
/**
25
45
* Constructor
26
46
* @param string $enumeration The classname of the enumeration type
@@ -29,7 +49,7 @@ class EnumMap extends SplObjectStorage
29
49
public function __construct ($ enumeration )
30
50
{
31
51
if (!\is_subclass_of ($ enumeration , Enum::class)) {
32
- throw new InvalidArgumentException (sprintf (
52
+ throw new InvalidArgumentException (\ sprintf (
33
53
"This EnumMap can handle subclasses of '%s' only " ,
34
54
Enum::class
35
55
));
@@ -55,8 +75,7 @@ public function getEnumeration()
55
75
*/
56
76
public function attach ($ enumerator , $ data = null )
57
77
{
58
- $ enumeration = $ this ->enumeration ;
59
- parent ::attach ($ enumeration ::get ($ enumerator ), $ data );
78
+ return $ this ->offsetSet ($ enumerator , $ data );
60
79
}
61
80
62
81
/**
@@ -66,13 +85,7 @@ public function attach($enumerator, $data = null)
66
85
*/
67
86
public function contains ($ enumerator )
68
87
{
69
- try {
70
- $ enumeration = $ this ->enumeration ;
71
- return parent ::contains ($ enumeration ::get ($ enumerator ));
72
- } catch (InvalidArgumentException $ e ) {
73
- // On an InvalidArgumentException the given argument can't be contained in this map
74
- return false ;
75
- }
88
+ return $ this ->offsetExists ($ enumerator );
76
89
}
77
90
78
91
/**
@@ -83,8 +96,7 @@ public function contains($enumerator)
83
96
*/
84
97
public function detach ($ enumerator )
85
98
{
86
- $ enumeration = $ this ->enumeration ;
87
- parent ::detach ($ enumeration ::get ($ enumerator ));
99
+ $ this ->offsetUnset ($ enumerator );
88
100
}
89
101
90
102
/**
@@ -95,7 +107,14 @@ public function detach($enumerator)
95
107
*/
96
108
public function offsetExists ($ enumerator )
97
109
{
98
- return $ this ->contains ($ enumerator );
110
+ try {
111
+ $ enumeration = $ this ->enumeration ;
112
+ $ ord = $ enumeration ::get ($ enumerator )->getOrdinal ();
113
+ return isset ($ this ->map [$ ord ]);
114
+ } catch (InvalidArgumentException $ e ) {
115
+ // An invalid enumerator can't be contained in this map
116
+ return false ;
117
+ }
99
118
}
100
119
101
120
/**
@@ -107,7 +126,15 @@ public function offsetExists($enumerator)
107
126
public function offsetGet ($ enumerator )
108
127
{
109
128
$ enumeration = $ this ->enumeration ;
110
- return parent ::offsetGet ($ enumeration ::get ($ enumerator ));
129
+ $ ord = $ enumeration ::get ($ enumerator )->getOrdinal ();
130
+ if (!isset ($ this ->map [$ ord ])) {
131
+ throw new UnexpectedValueException (\sprintf (
132
+ "Enumerator '%s' could not be found " ,
133
+ \is_object ($ enumerator ) ? $ enumerator ->getValue () : $ enumerator
134
+ ));
135
+ }
136
+
137
+ return $ this ->map [$ ord ];
111
138
}
112
139
113
140
/**
@@ -121,7 +148,12 @@ public function offsetGet($enumerator)
121
148
public function offsetSet ($ enumerator , $ data = null )
122
149
{
123
150
$ enumeration = $ this ->enumeration ;
124
- parent ::offsetSet ($ enumeration ::get ($ enumerator ), $ data );
151
+ $ ord = $ enumeration ::get ($ enumerator )->getOrdinal ();
152
+
153
+ if (!isset ($ this ->map [$ ord ])) {
154
+ $ this ->ordinals [] = $ ord ;
155
+ }
156
+ $ this ->map [$ ord ] = $ data ;
125
157
}
126
158
127
159
/**
@@ -134,7 +166,11 @@ public function offsetSet($enumerator, $data = null)
134
166
public function offsetUnset ($ enumerator )
135
167
{
136
168
$ enumeration = $ this ->enumeration ;
137
- parent ::offsetUnset ($ enumeration ::get ($ enumerator ));
169
+ $ ord = $ enumeration ::get ($ enumerator )->getOrdinal ();
170
+
171
+ if (($ idx = \array_search ($ ord , $ this ->ordinals , true )) !== false ) {
172
+ unset($ this ->map [$ ord ], $ this ->ordinals [$ idx ]);
173
+ }
138
174
}
139
175
140
176
/**
@@ -143,7 +179,11 @@ public function offsetUnset($enumerator)
143
179
*/
144
180
public function current ()
145
181
{
146
- return parent ::getInfo ();
182
+ if (!isset ($ this ->ordinals [$ this ->pos ])) {
183
+ return null ;
184
+ }
185
+
186
+ return $ this ->map [$ this ->ordinals [$ this ->pos ]];
147
187
}
148
188
149
189
/**
@@ -152,6 +192,48 @@ public function current()
152
192
*/
153
193
public function key ()
154
194
{
155
- return parent ::current ();
195
+ if (!isset ($ this ->ordinals [$ this ->pos ])) {
196
+ return null ;
197
+ }
198
+
199
+ $ enumeration = $ this ->enumeration ;
200
+ return $ enumeration ::byOrdinal ($ this ->ordinals [$ this ->pos ]);
201
+ }
202
+
203
+ /**
204
+ * Reset the iterator position to zero.
205
+ * @return void
206
+ */
207
+ public function rewind ()
208
+ {
209
+ $ this ->pos = 0 ;
210
+ }
211
+
212
+ /**
213
+ * Increment the iterator position by one.
214
+ * @return void
215
+ */
216
+ public function next ()
217
+ {
218
+ ++$ this ->pos ;
219
+ }
220
+
221
+ /**
222
+ * Test if the iterator is in a valid state
223
+ * @return boolean
224
+ */
225
+ public function valid ()
226
+ {
227
+ return isset ($ this ->ordinals [$ this ->pos ]);
228
+ }
229
+
230
+ /**
231
+ * Count the number of elements
232
+ *
233
+ * @return int
234
+ */
235
+ public function count ()
236
+ {
237
+ return \count ($ this ->ordinals );
156
238
}
157
239
}
0 commit comments