@@ -306,6 +306,7 @@ static void _const_string(smart_str *str, const char *name, zval *value, const c
306306static void _function_string (smart_str * str , zend_function * fptr , zend_class_entry * scope , const char * indent );
307307static void _property_string (smart_str * str , zend_property_info * prop , const char * prop_name , const char * indent );
308308static 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 );
309310static void _class_string (smart_str * str , zend_class_entry * ce , zval * obj , const char * indent );
310311static void _extension_string (smart_str * str , const zend_module_entry * module , const char * indent );
311312static 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
330331 kind = "Interface" ;
331332 } else if (ce -> ce_flags & ZEND_ACC_TRAIT ) {
332333 kind = "Trait" ;
334+ } else if (ce -> ce_flags & ZEND_ACC_ENUM ) {
335+ kind = "Enum" ;
333336 }
334337 smart_str_append_printf (str , "%s%s [ " , indent , kind );
335338 }
@@ -345,6 +348,8 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
345348 smart_str_append_printf (str , "interface " );
346349 } else if (ce -> ce_flags & ZEND_ACC_TRAIT ) {
347350 smart_str_append_printf (str , "trait " );
351+ } else if (ce -> ce_flags & ZEND_ACC_ENUM ) {
352+ smart_str_append_printf (str , "enum " );
348353 } else {
349354 if (ce -> ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS |ZEND_ACC_EXPLICIT_ABSTRACT_CLASS )) {
350355 smart_str_append_printf (str , "abstract " );
@@ -362,6 +367,14 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
362367 smart_str_append_printf (str , " extends %s" , ZSTR_VAL (ce -> parent -> name ));
363368 }
364369
370+ if ((ce -> ce_flags & ZEND_ACC_ENUM ) && (ce -> enum_backing_type != IS_UNDEF )) {
371+ // Show backing type
372+ if (ce -> enum_backing_type == IS_STRING ) {
373+ smart_str_append_printf (str , ": string" );
374+ } else {
375+ smart_str_append_printf (str , ": int" );
376+ }
377+ }
365378 if (ce -> num_interfaces ) {
366379 uint32_t i ;
367380
@@ -384,23 +397,58 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
384397 }
385398
386399 /* 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 ) {
400+ int total_count = zend_hash_num_elements (& ce -> constants_table );
401+ int constant_count = 0 ;
402+ int enum_case_count = 0 ;
403+ smart_str constant_str = {0 };
404+ smart_str enum_case_str = {0 };
405+ // So that we don't need to loop through all of the constants multiple
406+ // times (count the constants vs. enum cases, print the constants, print
407+ // the enum cases) use some temporary helper smart strings
408+ if (total_count > 0 ) {
391409 zend_string * key ;
392410 zend_class_constant * c ;
393411
394412 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (CE_CONSTANTS_TABLE (ce ), key , c ) {
395- _class_const_string (str , key , c , ZSTR_VAL (sub_indent ));
413+ if (Z_TYPE (c -> value ) == IS_CONSTANT_AST
414+ && zend_update_class_constant (c , key , c -> ce ) == FAILURE
415+ ) {
416+ ZEND_ASSERT (EG (exception ));
417+ zend_string_release (sub_indent );
418+ smart_str_free (& enum_case_str );
419+ smart_str_free (& constant_str );
420+ return ;
421+ }
422+ if (ZEND_CLASS_CONST_FLAGS (c ) & ZEND_CLASS_CONST_IS_CASE ) {
423+ _enum_case_string (& enum_case_str , key , c , ZSTR_VAL (sub_indent ));
424+ enum_case_count ++ ;
425+ } else {
426+ _class_const_string (& constant_str , key , c , ZSTR_VAL (sub_indent ));
427+ constant_count ++ ;
428+ }
396429 if (UNEXPECTED (EG (exception ))) {
397430 zend_string_release (sub_indent );
431+ smart_str_free (& enum_case_str );
432+ smart_str_free (& constant_str );
398433 return ;
399434 }
400435 } ZEND_HASH_FOREACH_END ();
401436 }
437+ // Enum cases go first, but the heading is only shown if there are any
438+ if (enum_case_count ) {
439+ smart_str_append_printf (str , "\n" );
440+ smart_str_append_printf (str , "%s - Enum cases [%d] {\n" , indent , enum_case_count );
441+ smart_str_append_smart_str (str , & enum_case_str );
442+ smart_str_append_printf (str , "%s }\n" , indent );
443+ }
444+ smart_str_append_printf (str , "\n" );
445+ smart_str_append_printf (str , "%s - Constants [%d] {\n" , indent , constant_count );
446+ smart_str_append_smart_str (str , & constant_str );
402447 smart_str_append_printf (str , "%s }\n" , indent );
403448
449+ smart_str_free (& enum_case_str );
450+ smart_str_free (& constant_str );
451+
404452 /* Static properties */
405453 /* counting static properties */
406454 count = zend_hash_num_elements (& ce -> properties_info );
@@ -626,6 +674,30 @@ static void _class_const_string(smart_str *str, const zend_string *name, zend_cl
626674}
627675/* }}} */
628676
677+ /* {{{ _enum_case_string */
678+ static void _enum_case_string (smart_str * str , const zend_string * name , zend_class_constant * c , const char * indent )
679+ {
680+ if (c -> doc_comment ) {
681+ smart_str_append_printf (str , "%s%s\n" , indent , ZSTR_VAL (c -> doc_comment ));
682+ }
683+ smart_str_append_printf (str , "%sCase %s" , indent , ZSTR_VAL (name ));
684+ if (c -> ce -> enum_backing_type == IS_UNDEF ) {
685+ // No value
686+ smart_str_appends (str , "\n" );
687+ } else {
688+ // Has a value, which is the enum instance, get the value from that.
689+ // We know it must be either a string or integer so no need
690+ // for the IS_ARRAY or IS_OBJECT handling that _class_const_string()
691+ // requires
692+ zval * enum_val = zend_enum_fetch_case_value (Z_OBJ (c -> value ));
693+ zend_string * tmp_value_str ;
694+ zend_string * value_str = zval_get_tmp_string (enum_val , & tmp_value_str );
695+ smart_str_append_printf (str , " = %s\n" , ZSTR_VAL (value_str ));
696+ zend_tmp_string_release (tmp_value_str );
697+ }
698+ }
699+ /* }}} */
700+
629701static zend_op * get_recv_op (const zend_op_array * op_array , uint32_t offset )
630702{
631703 zend_op * op = op_array -> opcodes ;
0 commit comments