Skip to content

Commit 978ee3a

Browse files
committed
optimized Enum::detectConstants()
1 parent 9019505 commit 978ee3a

File tree

7 files changed

+97
-32
lines changed

7 files changed

+97
-32
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ install:
4949

5050
script:
5151
- if [ "$CODE_COVERAGE" == "1" ]; then
52-
php vendor/bin/phpunit --verbose --coverage-text --coverage-clover=coverage.clover;
52+
php -d 'zend.assertions=1' vendor/bin/phpunit --verbose --coverage-text --coverage-clover=coverage.clover;
5353
else
54-
php vendor/bin/phpunit --verbose;
54+
php -d 'zend.assertions=1' vendor/bin/phpunit --verbose;
5555
fi
5656

5757
after_script:

bench/bootstrap.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
$zendassertions = ini_get('zend.assertions');
4+
if (\PHP_VERSION_ID >= 70000 && $zendassertions != -1) {
5+
echo 'Please disable zend.assertions in php.ini (zend.assertions = -1)' . PHP_EOL
6+
. "Current ini setting: zend.assertions = {$zendassertions}]" . PHP_EOL;
7+
exit(1);
8+
}
9+
assert_options(ASSERT_ACTIVE, 0);
10+
assert_options(ASSERT_WARNING, 0);
11+
assert_options(ASSERT_BAIL, 0);
12+
assert_options(ASSERT_QUIET_EVAL, 0);
13+
14+
require_once __DIR__ . '/../vendor/autoload.php';

phpbench.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"bootstrap": "vendor/autoload.php",
2+
"bootstrap": "bench/bootstrap.php",
33
"path": "bench/",
44
"retry_threshold": 5
55
}

phpunit.xml.dist

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@
2121
<directory suffix=".php">./src</directory>
2222
</whitelist>
2323
</filter>
24+
<php>
25+
<ini name="zend.assertions" value="1"/>
26+
<ini name="assert.exception" value="1"/>
27+
</php>
2428
</phpunit>

src/Enum.php

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace MabeEnum;
44

5+
use AssertionError;
56
use ReflectionClass;
67
use InvalidArgumentException;
78
use LogicException;
@@ -337,17 +338,17 @@ final public static function has($value)
337338
*
338339
* @param string $class
339340
* @return array
340-
* @throws LogicException On ambiguous constant values
341+
* @throws AssertionError On ambiguous constant values
341342
*/
342343
private static function detectConstants($class)
343344
{
344345
if (!isset(self::$constants[$class])) {
345346
$reflection = new ReflectionClass($class);
346-
$constants = [];
347+
$publicConstants = [];
347348

348349
do {
349350
$scopeConstants = [];
350-
if (PHP_VERSION_ID >= 70100) {
351+
if (\PHP_VERSION_ID >= 70100) {
351352
// Since PHP-7.1 visibility modifiers are allowed for class constants
352353
// for enumerations we are only interested in public once.
353354
foreach ($reflection->getReflectionConstants() as $reflConstant) {
@@ -360,33 +361,35 @@ private static function detectConstants($class)
360361
$scopeConstants = $reflection->getConstants();
361362
}
362363

363-
$constants = $scopeConstants + $constants;
364+
$publicConstants = $scopeConstants + $publicConstants;
364365
} while (($reflection = $reflection->getParentClass()) && $reflection->name !== __CLASS__);
365366

366-
// Detect ambiguous values and report names
367-
$ambiguous = [];
368-
foreach ($constants as $value) {
369-
$names = \array_keys($constants, $value, true);
370-
if (\count($names) > 1) {
371-
$ambiguous[\var_export($value, true)] = $names;
372-
}
373-
}
374-
if (!empty($ambiguous)) {
375-
throw new LogicException(
376-
'All possible values needs to be unique. The following are ambiguous: '
377-
. \implode(', ', \array_map(function ($names) use ($constants) {
378-
return \implode('/', $names) . '=' . \var_export($constants[$names[0]], true);
379-
}, $ambiguous))
380-
);
381-
}
367+
assert(self::noAmbiguousValues($publicConstants));
382368

383-
self::$constants[$class] = $constants;
384-
self::$names[$class] = \array_keys($constants);
369+
self::$constants[$class] = $publicConstants;
370+
self::$names[$class] = \array_keys($publicConstants);
385371
}
386372

387373
return self::$constants[$class];
388374
}
389375

376+
/**
377+
* Assert that the given enumeration class doesn't define ambiguous enumerator values
378+
* @param array $constants
379+
* @return bool
380+
*/
381+
private static function noAmbiguousValues(array $constants)
382+
{
383+
foreach ($constants as $value) {
384+
$names = \array_keys($constants, $value, true);
385+
if (\count($names) > 1) {
386+
return false;
387+
}
388+
}
389+
390+
return true;
391+
}
392+
390393
/**
391394
* Get an enumerator instance by the given name.
392395
*

tests/MabeEnumTest/EnumTest.php

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace MabeEnumTest;
44

5+
use AssertionError;
56
use InvalidArgumentException;
67
use LogicException;
78
use MabeEnum\Enum;
@@ -41,6 +42,11 @@ public function setUp()
4142
$instancesProp->setValue(null, []);
4243
}
4344

45+
public function tearDown()
46+
{
47+
assert_options(ASSERT_ACTIVE, 1);
48+
}
49+
4450
public function testGetNameReturnsConstantNameOfCurrentValue()
4551
{
4652
$enum = EnumBasic::get(EnumBasic::ONE);
@@ -274,15 +280,31 @@ public function testInstantiateUsingMagicMethod()
274280
$this->assertSame(EnumInheritance::ONE, $enum->getValue());
275281
}
276282

277-
public function testAmbiguousConstantsThrowsLogicException()
283+
public function testEnabledAssertAmbiguousEnumeratorValues()
278284
{
279-
$this->expectException(LogicException::class);
285+
$this->expectException(AssertionError::class);
280286
EnumAmbiguous::get('unknown');
281287
}
282288

283-
public function testExtendedAmbiguousCanstantsThrowsLogicException()
289+
public function testDisabledAssertAmbiguousEnumeratorValues()
284290
{
285-
$this->expectException(LogicException::class);
291+
assert_options(ASSERT_ACTIVE, 0);
292+
$this->expectException(InvalidArgumentException::class);
293+
294+
EnumAmbiguous::get('unknown');
295+
}
296+
297+
public function testExtendedEnabledAssertAmbiguousEnumeratorValues()
298+
{
299+
$this->expectException(AssertionError::class);
300+
EnumExtendedAmbiguous::get('unknown');
301+
}
302+
303+
public function testExtendedDisabledAssertAmbiguousEnumeratorValues()
304+
{
305+
assert_options(ASSERT_ACTIVE, 0);
306+
$this->expectException(InvalidArgumentException::class);
307+
286308
EnumExtendedAmbiguous::get('unknown');
287309
}
288310

tests/bootstrap.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
<?php
22

3-
ini_set('error_reporting', E_ALL);
3+
// report all errors
4+
error_reporting(E_ALL);
5+
6+
// make sure zend.assertions are available (not disabled on compile time)
7+
$zendassertions = ini_get('zend.assertions');
8+
if (\PHP_VERSION_ID >= 70000 && $zendassertions == -1) {
9+
echo 'Please enable zend.assertions in php.ini (zend.assertions = 1)' . PHP_EOL
10+
. "Current ini setting: zend.assertions = {$zendassertions}]" . PHP_EOL;
11+
exit(1);
12+
}
13+
14+
// activate assertions
15+
assert_options(ASSERT_ACTIVE, 1);
16+
assert_options(ASSERT_WARNING, 0);
17+
assert_options(ASSERT_BAIL, 0);
18+
assert_options(ASSERT_QUIET_EVAL, 0);
19+
if (!class_exists('AssertionError')) {
20+
// AssertionError has been added in PHP-7.0
21+
class AssertionError extends Exception {};
22+
}
23+
assert_options(ASSERT_CALLBACK, function($file, $line, $code) {
24+
throw new AssertionError("assert(): Assertion '{$code}' failed in {$file} on line {$line}");
25+
});
426

527
// installed itself
628
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
@@ -17,8 +39,8 @@
1739
}
1840

1941
// autload test files
20-
spl_autoload_register(function ($className) {
21-
$file = __DIR__ . '/' . str_replace('\\', '/', $className) . '.php';
42+
spl_autoload_register(function ($class) {
43+
$file = __DIR__ . '/' . str_replace('\\', '/', $class) . '.php';
2244
if (file_exists($file)) {
2345
require $file;
2446
}

0 commit comments

Comments
 (0)