1919#include "zend.h"
2020#include "zend_API.h"
2121#include "zend_compile.h"
22- #include "zend_interfaces_arginfo .h"
22+ #include "zend_enum_arginfo .h"
2323
2424#define ZEND_ENUM_PROPERTY_ERROR () \
2525 zend_throw_error(NULL, "Enum properties are immutable")
3131 } \
3232 } while (0);
3333
34+ ZEND_API zend_class_entry * zend_ce_unit_enum ;
35+ ZEND_API zend_class_entry * zend_ce_scalar_enum ;
36+
3437static zend_object_handlers enum_handlers ;
3538
3639zend_object * zend_enum_new (zval * result , zend_class_entry * ce , zend_string * case_name , zval * scalar_zv )
3740{
38- // Temporarily remove the ZEND_ACC_ENUM flag to allow instantiation
39- ce -> ce_flags &= ~ZEND_ACC_ENUM ;
40- object_init_ex (result , ce );
41- ce -> ce_flags |= ZEND_ACC_ENUM ;
41+ zend_object * zobj = zend_objects_new (ce );
42+ ZVAL_OBJ (result , zobj );
4243
43- zend_object * zobj = Z_OBJ_P (result );
4444 ZVAL_STR_COPY (OBJ_PROP_NUM (zobj , 0 ), case_name );
4545 if (scalar_zv != NULL ) {
4646 ZVAL_COPY (OBJ_PROP_NUM (zobj , 1 ), scalar_zv );
@@ -123,7 +123,7 @@ static zval *zend_enum_read_property(zend_object *zobj, zend_string *name, int t
123123 return zend_std_read_property (zobj , name , type , cache_slot , rv );
124124}
125125
126- ZEND_COLD zval * zend_enum_write_property (zend_object * object , zend_string * member , zval * value , void * * cache_slot )
126+ static ZEND_COLD zval * zend_enum_write_property (zend_object * object , zend_string * member , zval * value , void * * cache_slot )
127127{
128128 ZEND_ENUM_PROPERTY_ERROR ();
129129 return & EG (uninitialized_zval );
@@ -134,12 +134,12 @@ static ZEND_COLD void zend_enum_unset_property(zend_object *object, zend_string
134134 ZEND_ENUM_PROPERTY_ERROR ();
135135}
136136
137- ZEND_API zval * zend_enum_get_property_ptr_ptr (zend_object * zobj , zend_string * name , int type , void * * cache_slot )
137+ static zval * zend_enum_get_property_ptr_ptr (zend_object * zobj , zend_string * name , int type , void * * cache_slot )
138138{
139139 return NULL ;
140140}
141141
142- int zend_enum_compare_objects (zval * o1 , zval * o2 )
142+ static int zend_enum_compare_objects (zval * o1 , zval * o2 )
143143{
144144 if (Z_TYPE_P (o1 ) != IS_OBJECT || Z_TYPE_P (o2 ) != IS_OBJECT ) {
145145 return ZEND_UNCOMPARABLE ;
@@ -148,8 +148,46 @@ int zend_enum_compare_objects(zval *o1, zval *o2)
148148 return Z_OBJ_P (o1 ) == Z_OBJ_P (o2 ) ? 0 : 1 ;
149149}
150150
151+ static int zend_implement_unit_enum (zend_class_entry * interface , zend_class_entry * class_type )
152+ {
153+ if (class_type -> ce_flags & ZEND_ACC_ENUM ) {
154+ return SUCCESS ;
155+ }
156+
157+ zend_error_noreturn (E_ERROR , "Non-enum class %s cannot implement interface %s" ,
158+ ZSTR_VAL (class_type -> name ),
159+ ZSTR_VAL (interface -> name ));
160+
161+ return FAILURE ;
162+ }
163+
164+ static int zend_implement_scalar_enum (zend_class_entry * interface , zend_class_entry * class_type )
165+ {
166+ if (!(class_type -> ce_flags & ZEND_ACC_ENUM )) {
167+ zend_error_noreturn (E_ERROR , "Non-enum class %s cannot implement interface %s" ,
168+ ZSTR_VAL (class_type -> name ),
169+ ZSTR_VAL (interface -> name ));
170+ return FAILURE ;
171+ }
172+
173+ if (class_type -> enum_scalar_type == IS_UNDEF ) {
174+ zend_error_noreturn (E_ERROR , "Non-scalar enum %s cannot implement interface %s" ,
175+ ZSTR_VAL (class_type -> name ),
176+ ZSTR_VAL (interface -> name ));
177+ return FAILURE ;
178+ }
179+
180+ return SUCCESS ;
181+ }
182+
151183void zend_register_enum_ce (void )
152184{
185+ zend_ce_unit_enum = register_class_UnitEnum ();
186+ zend_ce_unit_enum -> interface_gets_implemented = zend_implement_unit_enum ;
187+
188+ zend_ce_scalar_enum = register_class_ScalarEnum (zend_ce_unit_enum );
189+ zend_ce_scalar_enum -> interface_gets_implemented = zend_implement_scalar_enum ;
190+
153191 memcpy (& enum_handlers , & std_object_handlers , sizeof (zend_object_handlers ));
154192 enum_handlers .read_property = zend_enum_read_property ;
155193 enum_handlers .write_property = zend_enum_write_property ;
@@ -190,8 +228,8 @@ static ZEND_NAMED_FUNCTION(zend_enum_cases_func)
190228
191229 array_init (return_value );
192230
193- ZEND_HASH_FOREACH_PTR (& ce -> constants_table , c ) {
194- if (!(c -> value . u2 . access_flags & ZEND_CLASS_CONST_IS_CASE )) {
231+ ZEND_HASH_FOREACH_PTR (CE_CONSTANTS_TABLE ( ce ) , c ) {
232+ if (!(Z_ACCESS_FLAGS ( c -> value ) & ZEND_CLASS_CONST_IS_CASE )) {
195233 continue ;
196234 }
197235 zval * zv = & c -> value ;
@@ -243,9 +281,8 @@ static void zend_enum_from_base(INTERNAL_FUNCTION_PARAMETERS, bool try)
243281 }
244282
245283 ZEND_ASSERT (Z_TYPE_P (case_name_zv ) == IS_STRING );
246- zval * case_const_zv = zend_hash_find (& ce -> constants_table , Z_STR_P (case_name_zv ));
247- ZEND_ASSERT (case_const_zv != NULL );
248- zend_class_constant * c = Z_PTR_P (case_const_zv );
284+ zend_class_constant * c = zend_hash_find_ptr (CE_CONSTANTS_TABLE (ce ), Z_STR_P (case_name_zv ));
285+ ZEND_ASSERT (c != NULL );
249286 zval * case_zv = & c -> value ;
250287 if (Z_TYPE_P (case_zv ) == IS_CONSTANT_AST ) {
251288 zval_update_constant_ex (case_zv , c -> ce );
@@ -269,45 +306,49 @@ static ZEND_NAMED_FUNCTION(zend_enum_try_from_func)
269306
270307void zend_enum_register_funcs (zend_class_entry * ce )
271308{
272- zend_string * cases_func_name = zend_string_init ("cases" , strlen ("cases" ), 1 );
273- zend_internal_function * cases_function = malloc (sizeof (zend_internal_function ));
309+ const uint32_t fn_flags =
310+ ZEND_ACC_PUBLIC |ZEND_ACC_STATIC |ZEND_ACC_HAS_RETURN_TYPE |ZEND_ACC_ARENA_ALLOCATED ;
311+ zend_internal_function * cases_function =
312+ zend_arena_alloc (& CG (arena ), sizeof (zend_internal_function ));
274313 memset (cases_function , 0 , sizeof (zend_internal_function ));
275314 cases_function -> type = ZEND_INTERNAL_FUNCTION ;
276315 cases_function -> module = EG (current_module );
277316 cases_function -> handler = zend_enum_cases_func ;
278- cases_function -> function_name = cases_func_name ;
317+ cases_function -> function_name = ZSTR_KNOWN ( ZEND_STR_CASES ) ;
279318 cases_function -> scope = ce ;
280- cases_function -> fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_HAS_RETURN_TYPE ;
319+ cases_function -> fn_flags = fn_flags ;
281320 cases_function -> arg_info = (zend_internal_arg_info * ) (arginfo_class_UnitEnum_cases + 1 );
282- zend_hash_add_ptr (& ce -> function_table , cases_func_name , cases_function );
321+ zend_hash_add_ptr (& ce -> function_table , ZSTR_KNOWN ( ZEND_STR_CASES ) , cases_function );
283322
284323 if (ce -> enum_scalar_type != IS_UNDEF ) {
285- zend_string * from_func_name = zend_string_init ( "from" , strlen ( "from" ), 1 );
286- zend_internal_function * from_function = malloc ( sizeof (zend_internal_function ));
324+ zend_internal_function * from_function =
325+ zend_arena_alloc ( & CG ( arena ), sizeof (zend_internal_function ));
287326 memset (from_function , 0 , sizeof (zend_internal_function ));
288327 from_function -> type = ZEND_INTERNAL_FUNCTION ;
289328 from_function -> module = EG (current_module );
290329 from_function -> handler = zend_enum_from_func ;
291- from_function -> function_name = from_func_name ;
330+ from_function -> function_name = ZSTR_KNOWN ( ZEND_STR_FROM ) ;
292331 from_function -> scope = ce ;
293- from_function -> fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_HAS_RETURN_TYPE ;
332+ from_function -> fn_flags = fn_flags ;
294333 from_function -> num_args = 1 ;
295334 from_function -> required_num_args = 1 ;
296335 from_function -> arg_info = (zend_internal_arg_info * ) (arginfo_class_ScalarEnum_from + 1 );
297- zend_hash_add_ptr (& ce -> function_table , from_func_name , from_function );
336+ zend_hash_add_ptr (& ce -> function_table , ZSTR_KNOWN ( ZEND_STR_FROM ) , from_function );
298337
299- zend_internal_function * try_from_function = malloc (sizeof (zend_internal_function ));
338+ zend_internal_function * try_from_function =
339+ zend_arena_alloc (& CG (arena ), sizeof (zend_internal_function ));
300340 memset (try_from_function , 0 , sizeof (zend_internal_function ));
301341 try_from_function -> type = ZEND_INTERNAL_FUNCTION ;
302342 try_from_function -> module = EG (current_module );
303343 try_from_function -> handler = zend_enum_try_from_func ;
304- try_from_function -> function_name = zend_string_init ( "tryFrom" , strlen ( "tryFrom" ), 1 );
344+ try_from_function -> function_name = ZSTR_KNOWN ( ZEND_STR_TRYFROM );
305345 try_from_function -> scope = ce ;
306- try_from_function -> fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_HAS_RETURN_TYPE ;
346+ try_from_function -> fn_flags = fn_flags ;
307347 try_from_function -> num_args = 1 ;
308348 try_from_function -> required_num_args = 1 ;
309349 try_from_function -> arg_info = (zend_internal_arg_info * ) (arginfo_class_ScalarEnum_tryFrom + 1 );
310- zend_hash_add_ptr (& ce -> function_table , zend_string_init ("tryfrom" , strlen ("tryfrom" ), 1 ), try_from_function );
350+ zend_hash_add_ptr (
351+ & ce -> function_table , ZSTR_KNOWN (ZEND_STR_TRYFROM_LOWERCASE ), try_from_function );
311352 }
312353}
313354
0 commit comments