@@ -23,20 +23,23 @@ final class Enum
2323 private EnumType $ type ;
2424
2525 /**
26- * @var null| string[]|int[]|float []
26+ * @var string[]|int[]
2727 */
28- private ? array $ values ;
28+ private array $ cases ;
2929
3030 /**
3131 * @param EnumName $name
3232 * @param EnumType $type
33- * @param null| string[]|int[]|float[] $values
33+ * @param string[]|int[] $cases
3434 */
35- public function __construct (EnumName $ name , EnumType $ type , ? array $ values )
35+ public function __construct (EnumName $ name , EnumType $ type , array $ cases )
3636 {
37+ if (empty ($ cases )) {
38+ throw new \InvalidArgumentException ('Enums must have at least one case, none given. ' , 1626541482 );
39+ }
3740 $ this ->name = $ name ;
3841 $ this ->type = $ type ;
39- $ this ->values = $ values ;
42+ $ this ->cases = $ cases ;
4043 }
4144
4245 /**
@@ -62,30 +65,34 @@ final class ' . $this->name->getName() . ' implements PseudoEnumInterface
6265{
6366 ' . $ this ->renderConstants () . '
6467
68+ /**
69+ * @var array< ' . $ this ->type . ',self>|self[]
70+ */
71+ private static array $instances;
72+
6573 private ' . $ this ->type . ' $value;
6674
6775 private function __construct( ' . $ this ->type . ' $value)
6876 {
6977 $this->value = $value;
7078 }
7179
72- public static function from ' . ucfirst (( string ) $ this -> type ) . ' ( ' . $ this ->type . ' ' . $ variable . '): self
80+ public static function from( ' . $ this ->type . ' ' . $ variable . '): self
7381 {
74- if (!in_array( ' . $ variable . ', array_map(function(self $case) {
75- return $case->getValue();
76- }, self::cases()))) {
77- throw ' . $ this ->name ->getExceptionName () . '::becauseItMustBeOneOfTheDefinedConstants( ' . $ variable . ');
82+ if (!isset(self::$instances[ ' . $ variable . '])) {
83+ ' . $ this ->renderValidation () . '
84+ self::$instances[ ' . $ variable . '] = new self( ' . $ variable . ');
7885 }
7986
80- return new self( ' . $ variable . ') ;
87+ return self::$instances[ ' . $ variable . '] ;
8188 }
8289
8390 ' . $ this ->renderNamedConstructors () . '
8491
8592 ' . $ this ->renderComparators () . '
8693
8794 /**
88- * @return array|self[]
95+ * @return array<int,self> |self[]
8996 */
9097 public static function cases(): array
9198 {
@@ -141,31 +148,43 @@ public static function becauseItMustBeOneOfTheDefinedConstants(' . $this->type .
141148 private function renderConstants (): string
142149 {
143150 $ constants = [];
144- if (is_array ($ this ->values )) {
145- foreach ($ this ->values as $ name => $ value ) {
146- $ renderedValue = $ this ->type ->isString ()
147- ? '\'' . $ value . '\''
148- : $ value ;
149- $ constants [] = 'const ' . $ this ->getConstantName ($ name ) . ' = ' . $ renderedValue . '; ' ;
150- }
151+ foreach ($ this ->cases as $ name => $ case ) {
152+ $ renderedValue = $ this ->type ->isString ()
153+ ? '\'' . $ case . '\''
154+ : $ case ;
155+ $ constants [] = 'const ' . $ this ->getConstantName ($ name ) . ' = ' . $ renderedValue . '; ' ;
151156 }
152157
153158 return trim (implode ("\n " , $ constants ));
154159 }
155160
161+ /**
162+ * @return string
163+ */
164+ private function renderValidation (): string
165+ {
166+ $ variable = '$ ' . $ this ->type ;
167+ $ caseChecks = [];
168+ foreach ($ this ->cases as $ name => $ value ) {
169+ $ caseChecks [] = $ variable . ' !== self:: ' . $ this ->getConstantName ($ name );
170+ }
171+
172+ return 'if ( ' . implode ("\n && " , $ caseChecks ) . ') {
173+ throw ' . $ this ->name ->getExceptionName () . '::becauseItMustBeOneOfTheDefinedConstants( ' . $ variable . ');
174+ } ' ;
175+ }
176+
156177 /**
157178 * @return string
158179 */
159180 private function renderNamedConstructors (): string
160181 {
161182 $ constructors = [];
162- if (is_array ($ this ->values )) {
163- foreach ($ this ->values as $ name => $ value ) {
164- $ constructors [] = 'public static function ' . $ name . '(): self
183+ foreach ($ this ->cases as $ name => $ case ) {
184+ $ constructors [] = 'public static function ' . $ name . '(): self
165185 {
166- return new self(self:: ' . $ this ->getConstantName ($ name ) . ');
186+ return self::from (self:: ' . $ this ->getConstantName ($ name ) . ');
167187 } ' ;
168- }
169188 }
170189
171190 return trim (implode ("\n\n " , $ constructors ));
@@ -177,13 +196,11 @@ private function renderNamedConstructors(): string
177196 private function renderComparators (): string
178197 {
179198 $ comparators = [];
180- if (is_array ($ this ->values )) {
181- foreach ($ this ->values as $ name => $ value ) {
182- $ comparators [] = 'public function getIs ' . ucfirst ($ name ) . '(): bool
199+ foreach ($ this ->cases as $ name => $ case ) {
200+ $ comparators [] = 'public function getIs ' . ucfirst ($ name ) . '(): bool
183201 {
184202 return $this->value === self:: ' . $ this ->getConstantName ($ name ) . ';
185203 } ' ;
186- }
187204 }
188205
189206 return trim (implode ("\n\n " , $ comparators ));
@@ -196,10 +213,8 @@ public function renderCases(): string
196213 {
197214 $ cases = [];
198215
199- if (is_array ($ this ->values )) {
200- foreach ($ this ->values as $ name => $ value ) {
201- $ cases [] = 'new self(self:: ' . $ this ->getConstantName ($ name ) . '), ' ;
202- }
216+ foreach ($ this ->cases as $ name => $ case ) {
217+ $ cases [] = 'self::from(self:: ' . $ this ->getConstantName ($ name ) . '), ' ;
203218 }
204219
205220 return trim (trim (implode ("\n " , $ cases )), ', ' );
0 commit comments