@@ -306,6 +306,7 @@ static void _const_string(smart_str *str, const char *name, zval *value, const c
306
306
static void _function_string (smart_str * str , zend_function * fptr , zend_class_entry * scope , const char * indent );
307
307
static void _property_string (smart_str * str , zend_property_info * prop , const char * prop_name , const char * indent );
308
308
static void _class_const_string (smart_str * str , const zend_string * name , zend_class_constant * c , const char * indent );
309
+ static void _enum_case_string (smart_str * str , const zend_string * name , zend_class_constant * c , const char * indent );
309
310
static void _class_string (smart_str * str , zend_class_entry * ce , zval * obj , const char * indent );
310
311
static void _extension_string (smart_str * str , const zend_module_entry * module , const char * indent );
311
312
static void _zend_extension_string (smart_str * str , const zend_extension * extension , const char * indent );
@@ -330,6 +331,8 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
330
331
kind = "Interface" ;
331
332
} else if (ce -> ce_flags & ZEND_ACC_TRAIT ) {
332
333
kind = "Trait" ;
334
+ } else if (ce -> ce_flags & ZEND_ACC_ENUM ) {
335
+ kind = "Enum" ;
333
336
}
334
337
smart_str_append_printf (str , "%s%s [ " , indent , kind );
335
338
}
@@ -345,6 +348,8 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
345
348
smart_str_append_printf (str , "interface " );
346
349
} else if (ce -> ce_flags & ZEND_ACC_TRAIT ) {
347
350
smart_str_append_printf (str , "trait " );
351
+ } else if (ce -> ce_flags & ZEND_ACC_ENUM ) {
352
+ smart_str_append_printf (str , "enum " );
348
353
} else {
349
354
if (ce -> ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS |ZEND_ACC_EXPLICIT_ABSTRACT_CLASS )) {
350
355
smart_str_append_printf (str , "abstract " );
@@ -362,18 +367,47 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
362
367
smart_str_append_printf (str , " extends %s" , ZSTR_VAL (ce -> parent -> name ));
363
368
}
364
369
365
- if (ce -> num_interfaces ) {
366
- uint32_t i ;
370
+ uint32_t num_interfaces = ce -> num_interfaces ;
371
+ if (ce -> ce_flags & ZEND_ACC_ENUM ) {
372
+ // Ignore `UnitEnum`
373
+ num_interfaces -- ;
374
+ if (ce -> enum_backing_type != IS_UNDEF ) {
375
+ // Ignore `BackedEnum`
376
+ num_interfaces -- ;
377
+ // And show backing type
378
+ if (ce -> enum_backing_type == IS_STRING ) {
379
+ smart_str_append_printf (str , ": string" );
380
+ } else {
381
+ smart_str_append_printf (str , ": int" );
382
+ }
383
+ }
384
+ }
385
+ if (num_interfaces ) {
386
+ uint32_t next_interface = 0 ;
367
387
368
388
ZEND_ASSERT (ce -> ce_flags & ZEND_ACC_LINKED );
389
+
390
+ #define IS_ENUM_INTERFACE (_iface ) (_iface == zend_ce_unit_enum || _iface == zend_ce_backed_enum)
391
+ if (ce -> ce_flags & ZEND_ACC_ENUM && IS_ENUM_INTERFACE (ce -> interfaces [0 ])) {
392
+ next_interface ++ ;
393
+ if (ce -> num_interfaces > 1 && IS_ENUM_INTERFACE (ce -> interfaces [1 ])) {
394
+ next_interface ++ ;
395
+ }
396
+ }
397
+
369
398
if (ce -> ce_flags & ZEND_ACC_INTERFACE ) {
370
399
smart_str_append_printf (str , " extends %s" , ZSTR_VAL (ce -> interfaces [0 ]-> name ));
371
400
} else {
372
- smart_str_append_printf (str , " implements %s" , ZSTR_VAL (ce -> interfaces [0 ]-> name ));
401
+ smart_str_append_printf (str , " implements %s" , ZSTR_VAL (ce -> interfaces [next_interface ]-> name ));
373
402
}
374
- for (i = 1 ; i < ce -> num_interfaces ; ++ i ) {
375
- smart_str_append_printf (str , ", %s" , ZSTR_VAL (ce -> interfaces [i ]-> name ));
403
+ next_interface ++ ;
404
+ // Going through the entire interface list, skipping the enum ones
405
+ for (; next_interface < ce -> num_interfaces ; ++ next_interface ) {
406
+ if (!IS_ENUM_INTERFACE (ce -> interfaces [next_interface ])) {
407
+ smart_str_append_printf (str , ", %s" , ZSTR_VAL (ce -> interfaces [next_interface ]-> name ));
408
+ }
376
409
}
410
+ #undef IS_ENUM_INTERFACE
377
411
}
378
412
smart_str_append_printf (str , " ] {\n" );
379
413
@@ -384,23 +418,58 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
384
418
}
385
419
386
420
/* Constants */
387
- smart_str_append_printf (str , "\n" );
388
- count = zend_hash_num_elements (& ce -> constants_table );
389
- smart_str_append_printf (str , "%s - Constants [%d] {\n" , indent , count );
390
- if (count > 0 ) {
421
+ int total_count = zend_hash_num_elements (& ce -> constants_table );
422
+ int constant_count = 0 ;
423
+ int enum_case_count = 0 ;
424
+ smart_str constant_str = {0 };
425
+ smart_str enum_case_str = {0 };
426
+ // So that we don't need to loop through all of the constants multiple
427
+ // times (count the constants vs. enum cases, print the constants, print
428
+ // the enum cases) use some temporary helper smart strings
429
+ if (total_count > 0 ) {
391
430
zend_string * key ;
392
431
zend_class_constant * c ;
393
432
394
433
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (CE_CONSTANTS_TABLE (ce ), key , c ) {
395
- _class_const_string (str , key , c , ZSTR_VAL (sub_indent ));
434
+ if (Z_TYPE (c -> value ) == IS_CONSTANT_AST
435
+ && zend_update_class_constant (c , key , c -> ce ) == FAILURE
436
+ ) {
437
+ ZEND_ASSERT (EG (exception ));
438
+ zend_string_release (sub_indent );
439
+ smart_str_free (& enum_case_str );
440
+ smart_str_free (& constant_str );
441
+ return ;
442
+ }
443
+ if (ZEND_CLASS_CONST_FLAGS (c ) & ZEND_CLASS_CONST_IS_CASE ) {
444
+ _enum_case_string (& enum_case_str , key , c , ZSTR_VAL (sub_indent ));
445
+ enum_case_count ++ ;
446
+ } else {
447
+ _class_const_string (& constant_str , key , c , ZSTR_VAL (sub_indent ));
448
+ constant_count ++ ;
449
+ }
396
450
if (UNEXPECTED (EG (exception ))) {
397
451
zend_string_release (sub_indent );
452
+ smart_str_free (& enum_case_str );
453
+ smart_str_free (& constant_str );
398
454
return ;
399
455
}
400
456
} ZEND_HASH_FOREACH_END ();
401
457
}
458
+ // Enum cases go first, but the heading is only shown if there are any
459
+ if (enum_case_count ) {
460
+ smart_str_append_printf (str , "\n" );
461
+ smart_str_append_printf (str , "%s - Enum cases [%d] {\n" , indent , enum_case_count );
462
+ smart_str_append_smart_str (str , & enum_case_str );
463
+ smart_str_append_printf (str , "%s }\n" , indent );
464
+ }
465
+ smart_str_append_printf (str , "\n" );
466
+ smart_str_append_printf (str , "%s - Constants [%d] {\n" , indent , constant_count );
467
+ smart_str_append_smart_str (str , & constant_str );
402
468
smart_str_append_printf (str , "%s }\n" , indent );
403
469
470
+ smart_str_free (& enum_case_str );
471
+ smart_str_free (& constant_str );
472
+
404
473
/* Static properties */
405
474
/* counting static properties */
406
475
count = zend_hash_num_elements (& ce -> properties_info );
@@ -626,6 +695,30 @@ static void _class_const_string(smart_str *str, const zend_string *name, zend_cl
626
695
}
627
696
/* }}} */
628
697
698
+ /* {{{ _enum_case_string */
699
+ static void _enum_case_string (smart_str * str , const zend_string * name , zend_class_constant * c , const char * indent )
700
+ {
701
+ if (c -> doc_comment ) {
702
+ smart_str_append_printf (str , "%s%s\n" , indent , ZSTR_VAL (c -> doc_comment ));
703
+ }
704
+ smart_str_append_printf (str , "%sCase %s" , indent , ZSTR_VAL (name ));
705
+ if (c -> ce -> enum_backing_type == IS_UNDEF ) {
706
+ // No value
707
+ smart_str_appends (str , "\n" );
708
+ } else {
709
+ // Has a value, which is the enum instance, get the value from that.
710
+ // We know it must be either a string or integer so no need
711
+ // for the IS_ARRAY or IS_OBJECT handling that _class_const_string()
712
+ // requires
713
+ zval * enum_val = zend_enum_fetch_case_value (Z_OBJ (c -> value ));
714
+ zend_string * tmp_value_str ;
715
+ zend_string * value_str = zval_get_tmp_string (enum_val , & tmp_value_str );
716
+ smart_str_append_printf (str , " = %s\n" , ZSTR_VAL (value_str ));
717
+ zend_tmp_string_release (tmp_value_str );
718
+ }
719
+ }
720
+ /* }}} */
721
+
629
722
static zend_op * get_recv_op (const zend_op_array * op_array , uint32_t offset )
630
723
{
631
724
zend_op * op = op_array -> opcodes ;
0 commit comments