Skip to content

Commit 75aa56b

Browse files
committed
Performance optimisations
1 parent b4a7b93 commit 75aa56b

File tree

1 file changed

+66
-58
lines changed

1 file changed

+66
-58
lines changed

src/MabeEnum/Enum.php

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,10 @@ abstract class Enum
4747
* @throws InvalidArgumentException On an unknwon or invalid value
4848
* @throws LogicException On ambiguous constant values
4949
*/
50-
final private function __construct($value)
50+
final private function __construct($value, $ordinal = null)
5151
{
52-
// find and set the given value
53-
// set the defined value because of non strict comparison
54-
$constants = static::getConstants();
55-
$const = array_search($value, $constants);
56-
if ($const === false) {
57-
throw new InvalidArgumentException("Unknown value '{$value}'");
58-
}
59-
$this->value = $constants[$const];
52+
$this->value = $value;
53+
$this->ordinal = $ordinal;
6054
}
6155

6256
/**
@@ -93,7 +87,7 @@ final public function getValue()
9387
*/
9488
final public function getName()
9589
{
96-
return array_search($this->value, $this::getConstants(), true);
90+
return array_search($this->value, self::detectConstants(get_called_class()), true);
9791
}
9892

9993
/**
@@ -109,7 +103,7 @@ final public function getOrdinal()
109103
// detect ordinal
110104
$ordinal = 0;
111105
$value = $this->value;
112-
foreach (static::getConstants() as $constValue) {
106+
foreach (self::detectConstants(get_called_class()) as $constValue) {
113107
if ($value === $constValue) {
114108
break;
115109
}
@@ -135,9 +129,14 @@ final static public function get($value)
135129
return self::$instances[$class][$value];
136130
}
137131

138-
$instance = new $class($value);
139-
self::$instances[$class][$value] = $instance;
140-
return $instance;
132+
// find the real value
133+
$constants = self::detectConstants($class);
134+
$name = array_search($value, $constants);
135+
if ($name === false) {
136+
throw new InvalidArgumentException("Unknown value '{$value}'");
137+
}
138+
139+
return self::$instances[$class][$value] = new $class($constants[$name]);
141140
}
142141

143142
/**
@@ -150,12 +149,18 @@ final static public function get($value)
150149
*/
151150
final public static function getByName($name)
152151
{
153-
$classConst = 'static::' . $name;
154-
if (!defined($classConst)) {
155-
$class = get_called_class();
156-
throw new InvalidArgumentException($class . '::' . $name . ' not defined');
152+
$class = get_called_class();
153+
$const = $class . '::' . $name;
154+
if (!defined($const)) {
155+
throw new InvalidArgumentException($const . ' not defined');
157156
}
158-
return static::get(constant($classConst));
157+
158+
$value = constant($const);
159+
if (isset(self::$instances[$class][$value])) {
160+
return self::$instances[$class][$value];
161+
}
162+
163+
return self::$instances[$class][$value] = new $class($value);
159164
}
160165

161166
/**
@@ -168,15 +173,23 @@ final public static function getByName($name)
168173
*/
169174
final public static function getByOrdinal($ordinal)
170175
{
171-
$constants = static::getConstants();
176+
$ordinal = (int) $ordinal;
177+
$class = get_called_class();
178+
$constants = self::detectConstants($class);
172179
$item = array_slice($constants, $ordinal, 1, false);
173180
if (!$item) {
174181
throw new InvalidArgumentException(sprintf(
175182
'Invalid ordinal number, must between 0 and %s',
176183
count($constants) - 1
177184
));
178185
}
179-
return static::get(current($item));
186+
187+
$value = current($item);
188+
if (isset(self::$instances[$class][$value])) {
189+
return self::$instances[$class][$value];
190+
}
191+
192+
return self::$instances[$class][$value] = new $class($value, $ordinal);
180193
}
181194

182195
/**
@@ -189,22 +202,8 @@ final public static function getByOrdinal($ordinal)
189202
*/
190203
final static public function clear()
191204
{
192-
$class = get_called_class();
193-
194-
// clear instantiated enums
195-
foreach (self::$instances as $instanceClass => $enum) {
196-
if (strcasecmp($class, $instanceClass) === 0) {
197-
unset(self::$instances[$instanceClass]);
198-
}
199-
}
200-
201-
// clear constants buffer
202-
foreach (self::$constants as $constantsClass => & $constants) {
203-
if (strcasecmp($class, $constantsClass) === 0) {
204-
unset(self::$constants[$constantsClass]);
205-
break;
206-
}
207-
}
205+
$class = get_called_class();
206+
unset(self::$instances[$class], self::$constants[$class]);
208207
}
209208

210209
/**
@@ -214,32 +213,41 @@ final static public function clear()
214213
*/
215214
final static public function getConstants()
216215
{
217-
$class = get_called_class();
218-
if (isset(self::$constants[$class])) {
219-
return self::$constants[$class];
220-
}
216+
return self::detectConstants(get_called_class());
217+
}
221218

222-
$reflection = new ReflectionClass($class);
223-
$constants = $reflection->getConstants();
219+
/**
220+
* Detect constants available by given class
221+
* @param string $class
222+
* @return void
223+
* @throws LogicException On ambiguous constant values
224+
*/
225+
static private function detectConstants($class)
226+
{
227+
if (!isset(self::$constants[$class])) {
228+
$reflection = new ReflectionClass($class);
229+
$constants = $reflection->getConstants();
224230

225-
// Constant values needs to be unique
226-
if (max(array_count_values($constants)) > 1) {
227-
$ambiguous = array_map(function ($v) use ($constants) {
228-
return implode('/', array_keys($constants, $v)) . '=' . $v;
229-
}, array_unique(array_diff_assoc($constants, array_unique($constants))));
230-
throw new LogicException(sprintf(
231-
'All possible values needs to be unique. The following are ambiguous: %s',
232-
implode(', ', $ambiguous)
233-
));
234-
}
231+
// Constant values needs to be unique
232+
if (max(array_count_values($constants)) > 1) {
233+
$ambiguous = array_map(function ($v) use ($constants) {
234+
return implode('/', array_keys($constants, $v)) . '=' . $v;
235+
}, array_unique(array_diff_assoc($constants, array_unique($constants))));
236+
throw new LogicException(sprintf(
237+
'All possible values needs to be unique. The following are ambiguous: %s',
238+
implode(', ', $ambiguous)
239+
));
240+
}
241+
242+
// This is required to make sure that constants of base classes will be the first
243+
while (($reflection = $reflection->getParentClass()) && $reflection->name != 'MabeEnum\Enum') {
244+
$constants = $reflection->getConstants() + $constants;
245+
}
235246

236-
// This is required to make sure that constants of base classes will be the first
237-
while ( ($reflection = $reflection->getParentClass()) ) {
238-
$constants = $reflection->getConstants() + $constants;
247+
self::$constants[$class] = $constants;
239248
}
240249

241-
self::$constants[$class] = $constants;
242-
return $constants;
250+
return self::$constants[$class];
243251
}
244252

245253
/**

0 commit comments

Comments
 (0)