Skip to content

Commit 91275df

Browse files
author
Marc Bennewitz
committed
Merge pull request #29 from marc-mabe/hotfix/strict_comparison
implemented strict comparison, fixes #28
2 parents 5731dd4 + 9f54402 commit 91275df

File tree

9 files changed

+234
-157
lines changed

9 files changed

+234
-157
lines changed

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ It's an abstract class that needs to be extended to use it.
2323
> particular concrete representation in the computer's memory; compilers and
2424
> interpreters can represent them arbitrarily.
2525
26+
2627
# Usage
2728

2829
## Basics
@@ -35,6 +36,13 @@ It's an abstract class that needs to be extended to use it.
3536
const INACTIVE = 0;
3637
const ACTIVE = 1;
3738
const DELETED = 2;
39+
40+
// all scalar datatypes are supported
41+
const NIL = null;
42+
const BOOLEAN = true;
43+
const INT = 1234;
44+
const STR = 'string';
45+
const FLOAT = 0.123;
3846
}
3947

4048
// different ways to instantiate an enumeration
@@ -89,7 +97,7 @@ Internally the ```EnumMap``` is based of ```SplObjectStorage```.
8997
// create a new EnumMap
9098
$enumMap = new EnumMap('UserStatus');
9199

92-
// attach entries (by value of by instance)
100+
// attach entries (by value or by instance)
93101
$enumMap->attach(UserStatus::INACTIVE, 'inaktiv');
94102
$enumMap->attach(UserStatus::ACTIVE(), 'aktiv');
95103
$enumMap->attach(UserStatus::DELETED(), 'gelöscht');
@@ -117,7 +125,7 @@ Internally it's based of a list (array) of ordinal values.
117125
// create a new EnumSet
118126
$enumSet = new EnumSet('UserStatus');
119127

120-
// attach entries (by value of by instance)
128+
// attach entries (by value or by instance)
121129
$enumSet->attach(UserStatus::INACTIVE);
122130
$enumSet->attach(UserStatus::ACTIVE());
123131
$enumSet->attach(UserStatus::DELETED());
@@ -129,6 +137,7 @@ Internally it's based of a list (array) of ordinal values.
129137
// iterate
130138
var_dump(iterator_to_array($enumSet)); // array(0 => UserStatus{$value=1});
131139

140+
132141
# Why not ```SplEnum```
133142

134143
* ```SplEnum``` is not build-in into PHP and requires pecl extension installed.

src/MabeEnum/Enum.php

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,22 @@ final public function getOrdinal()
122122
*/
123123
final static public function get($value)
124124
{
125-
$class = get_called_class();
126-
if (isset(self::$instances[$class][$value])) {
127-
return self::$instances[$class][$value];
128-
}
129-
130-
// find the real value
125+
$class = get_called_class();
131126
$constants = self::detectConstants($class);
132-
$name = array_search($value, $constants);
127+
$name = array_search($value, $constants, true);
133128
if ($name === false) {
134-
throw new InvalidArgumentException("Unknown value '{$value}'");
129+
if (is_scalar($value)) {
130+
throw new InvalidArgumentException('Unknown value ' . var_export($value, true));
131+
} else {
132+
throw new InvalidArgumentException('Invalid value of type ' . gettype($value));
133+
}
134+
}
135+
136+
if (isset(self::$instances[$class][$name])) {
137+
return self::$instances[$class][$name];
135138
}
136139

137-
return self::$instances[$class][$value] = new $class($constants[$name]);
140+
return self::$instances[$class][$name] = new $class($constants[$name]);
138141
}
139142

140143
/**
@@ -147,18 +150,18 @@ final static public function get($value)
147150
*/
148151
final public static function getByName($name)
149152
{
153+
$name = (string) $name;
150154
$class = get_called_class();
155+
if (isset(self::$instances[$class][$name])) {
156+
return self::$instances[$class][$name];
157+
}
158+
151159
$const = $class . '::' . $name;
152160
if (!defined($const)) {
153161
throw new InvalidArgumentException($const . ' not defined');
154162
}
155163

156-
$value = constant($const);
157-
if (isset(self::$instances[$class][$value])) {
158-
return self::$instances[$class][$value];
159-
}
160-
161-
return self::$instances[$class][$value] = new $class($value);
164+
return self::$instances[$class][$name] = new $class(constant($const));
162165
}
163166

164167
/**
@@ -182,12 +185,12 @@ final public static function getByOrdinal($ordinal)
182185
));
183186
}
184187

185-
$value = current($item);
186-
if (isset(self::$instances[$class][$value])) {
187-
return self::$instances[$class][$value];
188+
$name = key($item);
189+
if (isset(self::$instances[$class][$name])) {
190+
return self::$instances[$class][$name];
188191
}
189192

190-
return self::$instances[$class][$value] = new $class($value, $ordinal);
193+
return self::$instances[$class][$name] = new $class(current($item), $ordinal);
191194
}
192195

193196
/**
@@ -226,19 +229,25 @@ static private function detectConstants($class)
226229
$reflection = new ReflectionClass($class);
227230
$constants = $reflection->getConstants();
228231

229-
// Constant values needs to be unique
230-
if (max(array_count_values($constants)) > 1) {
231-
$ambiguous = array_map(function ($v) use ($constants) {
232-
return implode('/', array_keys($constants, $v)) . '=' . $v;
233-
}, array_unique(array_diff_assoc($constants, array_unique($constants))));
234-
throw new LogicException(sprintf(
235-
'All possible values needs to be unique. The following are ambiguous: %s',
236-
implode(', ', $ambiguous)
237-
));
232+
// values needs to be unique
233+
$ambiguous = array();
234+
foreach ($constants as $value) {
235+
$names = array_keys($constants, $value, true);
236+
if (count($names) > 1) {
237+
$ambiguous[var_export($value, true)] = $names;
238+
}
239+
}
240+
if ($ambiguous) {
241+
throw new LogicException(
242+
'All possible values needs to be unique. The following are ambiguous: '
243+
. implode(', ', array_map(function ($names) use ($constants) {
244+
return implode('/', $names) . '=' . var_export($constants[$names[0]], true);
245+
}, $ambiguous))
246+
);
238247
}
239248

240249
// This is required to make sure that constants of base classes will be the first
241-
while (($reflection = $reflection->getParentClass()) && $reflection->name != 'MabeEnum\Enum') {
250+
while (($reflection = $reflection->getParentClass()) && $reflection->name != __CLASS__) {
242251
$constants = $reflection->getConstants() + $constants;
243252
}
244253

tests/MabeEnumTest/EnumMapTest.php

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use MabeEnum\Enum;
66
use MabeEnum\EnumMap;
7-
use MabeEnumTest\TestAsset\EnumWithoutDefaultValue;
7+
use MabeEnumTest\TestAsset\EnumBasic;
88
use MabeEnumTest\TestAsset\EnumInheritance;
99
use PHPUnit_Framework_TestCase as TestCase;
1010
use ReflectionClass;
@@ -20,13 +20,13 @@ class EnumMapTest extends TestCase
2020
{
2121
public function testBasic()
2222
{
23-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
24-
$this->assertSame('MabeEnumTest\TestAsset\EnumWithoutDefaultValue', $enumMap->getEnumClass());
23+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
24+
$this->assertSame('MabeEnumTest\TestAsset\EnumBasic', $enumMap->getEnumClass());
2525

26-
$enum1 = EnumWithoutDefaultValue::ONE();
26+
$enum1 = EnumBasic::ONE();
2727
$value1 = 'value1';
2828

29-
$enum2 = EnumWithoutDefaultValue::TWO();
29+
$enum2 = EnumBasic::TWO();
3030
$value2 = 'value2';
3131

3232
$this->assertFalse($enumMap->contains($enum1));
@@ -50,25 +50,25 @@ public function testBasic()
5050

5151
public function testBasicWithConstantValuesAsEnums()
5252
{
53-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
53+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
5454

55-
$enum1 = EnumWithoutDefaultValue::ONE;
55+
$enum1 = EnumBasic::ONE;
5656
$value1 = 'value1';
5757

58-
$enum2 = EnumWithoutDefaultValue::TWO;
58+
$enum2 = EnumBasic::TWO;
5959
$value2 = 'value2';
6060

6161
$this->assertFalse($enumMap->contains($enum1));
6262
$this->assertNull($enumMap->attach($enum1, $value1));
6363
$this->assertTrue($enumMap->contains($enum1));
6464
$this->assertSame($value1, $enumMap[$enum1]);
65-
$this->assertSame(spl_object_hash(EnumWithoutDefaultValue::ONE()), $enumMap->getHash($enum1));
65+
$this->assertSame(spl_object_hash(EnumBasic::ONE()), $enumMap->getHash($enum1));
6666

6767
$this->assertFalse($enumMap->contains($enum2));
6868
$this->assertNull($enumMap->attach($enum2, $value2));
6969
$this->assertTrue($enumMap->contains($enum2));
7070
$this->assertSame($value2, $enumMap[$enum2]);
71-
$this->assertSame(spl_object_hash(EnumWithoutDefaultValue::TWO()), $enumMap->getHash($enum2));
71+
$this->assertSame(spl_object_hash(EnumBasic::TWO()), $enumMap->getHash($enum2));
7272

7373
$this->assertNull($enumMap->detach($enum1));
7474
$this->assertFalse($enumMap->contains($enum1));
@@ -79,12 +79,12 @@ public function testBasicWithConstantValuesAsEnums()
7979

8080
public function testIterate()
8181
{
82-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
82+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
8383

84-
$enum1 = EnumWithoutDefaultValue::ONE();
84+
$enum1 = EnumBasic::ONE();
8585
$value1 = 'value1';
8686

87-
$enum2 = EnumWithoutDefaultValue::TWO();
87+
$enum2 = EnumBasic::TWO();
8888
$value2 = 'value2';
8989

9090
// an empty enum map needs to be invalid, starting by 0
@@ -124,23 +124,23 @@ public function testIterate()
124124
public function testIterateWithFlags()
125125
{
126126
$enumMap = new EnumMap(
127-
'MabeEnumTest\TestAsset\EnumWithoutDefaultValue',
127+
'MabeEnumTest\TestAsset\EnumBasic',
128128
EnumMap::KEY_AS_INDEX | EnumMap::CURRENT_AS_ENUM
129129
);
130130

131-
$enumMap->attach(EnumWithoutDefaultValue::TWO(), 'first');
132-
$enumMap->attach(EnumWithoutDefaultValue::ONE(), 'second');
131+
$enumMap->attach(EnumBasic::TWO(), 'first');
132+
$enumMap->attach(EnumBasic::ONE(), 'second');
133133

134134
// EnumMap::KEY_AS_INDEX | EnumMap::CURRENT_AS_ENUM (first)
135135
$this->assertSame(EnumMap::KEY_AS_INDEX | EnumMap::CURRENT_AS_ENUM, $enumMap->getFlags());
136136

137137
$enumMap->rewind();
138138
$this->assertSame(0, $enumMap->key());
139-
$this->assertSame(EnumWithoutDefaultValue::TWO(), $enumMap->current());
139+
$this->assertSame(EnumBasic::TWO(), $enumMap->current());
140140

141141
$enumMap->next();
142142
$this->assertSame(1, $enumMap->key());
143-
$this->assertSame(EnumWithoutDefaultValue::ONE(), $enumMap->current());
143+
$this->assertSame(EnumBasic::ONE(), $enumMap->current());
144144

145145
// EnumMap::KEY_AS_NAME | EnumMap::CURRENT_AS_DATA
146146
$enumMap->setFlags(EnumMap::KEY_AS_NAME | EnumMap::CURRENT_AS_DATA);
@@ -205,40 +205,40 @@ public function testIterateWithFlags()
205205

206206
public function testArrayAccessWithObjects()
207207
{
208-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
208+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
209209

210-
$enumMap[EnumWithoutDefaultValue::ONE()] = 'first';
211-
$enumMap[EnumWithoutDefaultValue::TWO()] = 'second';
210+
$enumMap[EnumBasic::ONE()] = 'first';
211+
$enumMap[EnumBasic::TWO()] = 'second';
212212

213-
$this->assertTrue(isset($enumMap[EnumWithoutDefaultValue::ONE()]));
214-
$this->assertTrue(isset($enumMap[EnumWithoutDefaultValue::TWO()]));
213+
$this->assertTrue(isset($enumMap[EnumBasic::ONE()]));
214+
$this->assertTrue(isset($enumMap[EnumBasic::TWO()]));
215215

216-
$this->assertSame('first', $enumMap[EnumWithoutDefaultValue::ONE()]);
217-
$this->assertSame('second', $enumMap[EnumWithoutDefaultValue::TWO()]);
216+
$this->assertSame('first', $enumMap[EnumBasic::ONE()]);
217+
$this->assertSame('second', $enumMap[EnumBasic::TWO()]);
218218

219-
unset($enumMap[EnumWithoutDefaultValue::ONE()], $enumMap[EnumWithoutDefaultValue::TWO()]);
219+
unset($enumMap[EnumBasic::ONE()], $enumMap[EnumBasic::TWO()]);
220220

221-
$this->assertFalse(isset($enumMap[EnumWithoutDefaultValue::ONE()]));
222-
$this->assertFalse(isset($enumMap[EnumWithoutDefaultValue::TWO()]));
221+
$this->assertFalse(isset($enumMap[EnumBasic::ONE()]));
222+
$this->assertFalse(isset($enumMap[EnumBasic::TWO()]));
223223
}
224224

225225
public function testArrayAccessWithValues()
226226
{
227-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
227+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
228228

229-
$enumMap[EnumWithoutDefaultValue::ONE] = 'first';
230-
$enumMap[EnumWithoutDefaultValue::TWO] = 'second';
229+
$enumMap[EnumBasic::ONE] = 'first';
230+
$enumMap[EnumBasic::TWO] = 'second';
231231

232-
$this->assertTrue(isset($enumMap[EnumWithoutDefaultValue::ONE]));
233-
$this->assertTrue(isset($enumMap[EnumWithoutDefaultValue::TWO]));
232+
$this->assertTrue(isset($enumMap[EnumBasic::ONE]));
233+
$this->assertTrue(isset($enumMap[EnumBasic::TWO]));
234234

235-
$this->assertSame('first', $enumMap[EnumWithoutDefaultValue::ONE]);
236-
$this->assertSame('second', $enumMap[EnumWithoutDefaultValue::TWO]);
235+
$this->assertSame('first', $enumMap[EnumBasic::ONE]);
236+
$this->assertSame('second', $enumMap[EnumBasic::TWO]);
237237

238-
unset($enumMap[EnumWithoutDefaultValue::ONE], $enumMap[EnumWithoutDefaultValue::TWO]);
238+
unset($enumMap[EnumBasic::ONE], $enumMap[EnumBasic::TWO]);
239239

240-
$this->assertFalse(isset($enumMap[EnumWithoutDefaultValue::ONE]));
241-
$this->assertFalse(isset($enumMap[EnumWithoutDefaultValue::TWO]));
240+
$this->assertFalse(isset($enumMap[EnumBasic::ONE]));
241+
$this->assertFalse(isset($enumMap[EnumBasic::TWO]));
242242
}
243243

244244
public function testConstructThrowsInvalidArgumentExceptionIfEnumClassDoesNotExtendBaseEnum()
@@ -249,16 +249,16 @@ public function testConstructThrowsInvalidArgumentExceptionIfEnumClassDoesNotExt
249249

250250
public function testSetFlagsThrowsInvalidArgumentExceptionOnUnsupportedKeyFlag()
251251
{
252-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
252+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
253253

254254
$this->setExpectedException('InvalidArgumentException');
255255
$enumMap->setFlags(5);
256256
}
257257

258258
public function testCurrentThrowsRuntimeExceptionOnInvalidFlag()
259259
{
260-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
261-
$enumMap->attach(EnumWithoutDefaultValue::ONE());
260+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
261+
$enumMap->attach(EnumBasic::ONE());
262262
$enumMap->rewind();
263263

264264
// change internal flags to an invalid current flag
@@ -273,8 +273,8 @@ public function testCurrentThrowsRuntimeExceptionOnInvalidFlag()
273273

274274
public function testKeyThrowsRuntimeExceptionOnInvalidFlag()
275275
{
276-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
277-
$enumMap->attach(EnumWithoutDefaultValue::ONE());
276+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
277+
$enumMap->attach(EnumBasic::ONE());
278278
$enumMap->rewind();
279279

280280
// change internal flags to an invalid current flag
@@ -289,23 +289,23 @@ public function testKeyThrowsRuntimeExceptionOnInvalidFlag()
289289

290290
public function testSetFlagsThrowsInvalidArgumentExceptionOnUnsupportedCurrentFlag()
291291
{
292-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
292+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
293293

294294
$this->setExpectedException('InvalidArgumentException');
295295
$enumMap->setFlags(48);
296296
}
297297

298298
public function testInitEnumThrowsInvalidArgumentExceptionOnInvalidEnumGiven()
299299
{
300-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
300+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
301301

302302
$this->setExpectedException('InvalidArgumentException');
303303
$enumMap->offsetSet(EnumInheritance::INHERITANCE(), 'test');
304304
}
305305

306306
public function testContainsAndOffsetExistsReturnsFalseOnInvalidEnum()
307307
{
308-
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumWithoutDefaultValue');
308+
$enumMap = new EnumMap('MabeEnumTest\TestAsset\EnumBasic');
309309

310310
$this->assertFalse($enumMap->contains(EnumInheritance::INHERITANCE()));
311311
$this->assertFalse($enumMap->contains(EnumInheritance::INHERITANCE));

0 commit comments

Comments
 (0)