1010 * After using this Trait, the class can define public static "factory" methods to define its instances.
1111 *
1212 * For example, here is a very simple implementation:
13- * ```
13+ * ```php
1414 * class FooBarEnum implements EnumInterface
1515 * {
1616 * use EnumTrait;
@@ -72,7 +72,7 @@ trait EnumTrait /* implements EnumInterface */
7272{
7373 private static $ instancesById ;
7474
75- /** @var array */
75+ /** @var int[] */
7676 private static $ allInstancesInitialized = [];
7777
7878 /**
@@ -99,14 +99,30 @@ final protected static function define(string $id, ...$constructorArguments)
9999 return self ::$ instancesById [static ::class][$ id ];
100100 }
101101
102+ /**
103+ * This method is called the first time it's needed.
104+ * It should call `define` for each instance to be created.
105+ *
106+ * The default behavior is to call every public factory method in the class, with
107+ * the expectation that those methods will call `define`. Override this method to provide
108+ * different behavior, for instance loading instances parametrically from an array or file.
109+ *
110+ * If you override this method, the class must be final, because child classes won't be able
111+ * to add instances.
112+ */
113+ protected static function defineInstances (): void
114+ {
115+ call_all_public_nullary_factory_methods (static ::class);
116+ }
117+
102118 /**
103119 * @param string $id
104120 * @param bool $throwIfNotFound
105121 * @return null|$this
106122 */
107123 final public static function instance (string $ id , bool $ throwIfNotFound = false )
108124 {
109- static ::_ensureAllInstancesInitialized (static ::class );
125+ static ::_ensureAllInstancesInitialized ();
110126
111127 if (isset (self ::$ instancesById [static ::class][$ id ])) {
112128 return self ::$ instancesById [static ::class][$ id ];
@@ -124,42 +140,39 @@ final public static function instance(string $id, bool $throwIfNotFound = false)
124140 */
125141 final public static function instances (): array
126142 {
127- static ::_ensureAllInstancesInitialized (static ::class );
143+ static ::_ensureAllInstancesInitialized ();
128144
129145 return array_values (self ::$ instancesById [static ::class]);
130146 }
131147
132148 final public function getId (): string
133149 {
134- static ::_ensureAllInstancesInitialized (static ::class );
150+ static ::_ensureAllInstancesInitialized ();
135151
136- foreach (self ::$ instancesById [static ::class] as $ id => $ instance ) {
137- if ($ instance === $ this ) {
138- return $ id ;
139- }
140- }
141-
142- return null ;
152+ return array_search ($ this , self ::$ instancesById [static ::class], true );
143153 }
144154
145- private static function _ensureAllInstancesInitialized (string $ class ): void
155+ private static function _ensureAllInstancesInitialized (): void
146156 {
147- if (!isset (self ::$ allInstancesInitialized [$ class ])) {
148- initialize_all_enum_instances ($ class );
149- self ::$ allInstancesInitialized [$ class ] = true ;
157+ static $ _isInitializing ;
158+ if (!$ _isInitializing && !isset (self ::$ allInstancesInitialized [static ::class])) {
159+ $ _isInitializing = true ;
160+ static ::defineInstances ();
161+ $ _isInitializing = false ;
162+ self ::$ allInstancesInitialized [static ::class] = true ;
150163 }
151164 }
152165}
153166
154- function initialize_all_enum_instances (string $ enumClass ): void
167+ function call_all_public_nullary_factory_methods (string $ enumClass ): void
155168{
156169 try {
157170 $ reflectionClass = new \ReflectionClass ($ enumClass );
158171
159172 /** @var \ReflectionMethod[] $factoryMethods */
160173 $ factoryMethods = array_filter (
161174 $ reflectionClass ->getMethods (),
162- 'SolidPhp\ValueObjects\Enum\is_enum_factory_method '
175+ 'SolidPhp\ValueObjects\Enum\is_public_nullary_factory_method '
163176 );
164177 foreach ($ factoryMethods as $ method ) {
165178 $ method ->invoke (null );
@@ -169,7 +182,7 @@ function initialize_all_enum_instances(string $enumClass): void
169182 }
170183}
171184
172- function is_enum_factory_method (\ReflectionMethod $ method ): bool
185+ function is_public_nullary_factory_method (\ReflectionMethod $ method ): bool
173186{
174187 return $ method ->isPublic ()
175188 && $ method ->isStatic ()
0 commit comments