20
20
#include "zend_API.h"
21
21
#include "zend_compile.h"
22
22
#include "zend_enum_arginfo.h"
23
+ #include "zend_interfaces_arginfo.h"
23
24
#include "zend_interfaces.h"
24
25
#include "zend_enum.h"
25
26
@@ -81,11 +82,14 @@ static void zend_verify_enum_magic_methods(zend_class_entry *ce)
81
82
ZEND_ENUM_DISALLOW_MAGIC_METHOD (__set , "__set" );
82
83
ZEND_ENUM_DISALLOW_MAGIC_METHOD (__unset , "__unset" );
83
84
ZEND_ENUM_DISALLOW_MAGIC_METHOD (__isset , "__isset" );
84
- ZEND_ENUM_DISALLOW_MAGIC_METHOD (__tostring , "__toString" );
85
85
ZEND_ENUM_DISALLOW_MAGIC_METHOD (__debugInfo , "__debugInfo" );
86
86
ZEND_ENUM_DISALLOW_MAGIC_METHOD (__serialize , "__serialize" );
87
87
ZEND_ENUM_DISALLOW_MAGIC_METHOD (__unserialize , "__unserialize" );
88
88
89
+ if (ce -> enum_backing_type != IS_STRING ) {
90
+ ZEND_ENUM_DISALLOW_MAGIC_METHOD (__tostring , "__toString" );
91
+ }
92
+
89
93
const char * forbidden_methods [] = {
90
94
"__sleep" ,
91
95
"__wakeup" ,
@@ -169,6 +173,10 @@ void zend_enum_add_interfaces(zend_class_entry *ce)
169
173
ce -> num_interfaces ++ ;
170
174
if (ce -> enum_backing_type != IS_UNDEF ) {
171
175
ce -> num_interfaces ++ ;
176
+
177
+ if (ce -> enum_backing_type == IS_STRING ) {
178
+ ce -> num_interfaces ++ ;
179
+ }
172
180
}
173
181
174
182
ZEND_ASSERT (!(ce -> ce_flags & ZEND_ACC_RESOLVED_INTERFACES ));
@@ -181,6 +189,11 @@ void zend_enum_add_interfaces(zend_class_entry *ce)
181
189
if (ce -> enum_backing_type != IS_UNDEF ) {
182
190
ce -> interface_names [num_interfaces_before + 1 ].name = zend_string_copy (zend_ce_backed_enum -> name );
183
191
ce -> interface_names [num_interfaces_before + 1 ].lc_name = zend_string_init ("backedenum" , sizeof ("backedenum" ) - 1 , 0 );
192
+
193
+ if (ce -> enum_backing_type == IS_STRING ) {
194
+ ce -> interface_names [num_interfaces_before + 2 ].name = zend_string_copy (zend_ce_stringable -> name );
195
+ ce -> interface_names [num_interfaces_before + 2 ].lc_name = zend_string_init ("stringable" , sizeof ("stringable" ) - 1 , 0 );
196
+ }
184
197
}
185
198
}
186
199
@@ -394,6 +407,16 @@ static ZEND_NAMED_FUNCTION(zend_enum_try_from_func)
394
407
zend_enum_from_base (INTERNAL_FUNCTION_PARAM_PASSTHRU , 1 );
395
408
}
396
409
410
+ static ZEND_NAMED_FUNCTION (zend_enum_tostring_func )
411
+ {
412
+ ZEND_PARSE_PARAMETERS_NONE ();
413
+
414
+ zval * value = zend_enum_fetch_case_value (Z_OBJ_P (ZEND_THIS ));
415
+ ZEND_ASSERT (Z_TYPE_P (value ) == IS_STRING );
416
+
417
+ RETURN_COPY (value );
418
+ }
419
+
397
420
void zend_enum_register_funcs (zend_class_entry * ce )
398
421
{
399
422
const uint32_t fn_flags =
@@ -447,6 +470,28 @@ void zend_enum_register_funcs(zend_class_entry *ce)
447
470
zend_error_noreturn (E_COMPILE_ERROR ,
448
471
"Cannot redeclare %s::tryFrom()" , ZSTR_VAL (ce -> name ));
449
472
}
473
+
474
+ if (ce -> enum_backing_type == IS_STRING ) {
475
+ zend_internal_function * tostring_function =
476
+ zend_arena_alloc (& CG (arena ), sizeof (zend_internal_function ));
477
+ memset (tostring_function , 0 , sizeof (zend_internal_function ));
478
+ tostring_function -> type = ZEND_INTERNAL_FUNCTION ;
479
+ tostring_function -> module = EG (current_module );
480
+ tostring_function -> handler = zend_enum_tostring_func ;
481
+ tostring_function -> function_name = ZSTR_KNOWN (ZEND_STR_TOSTRING );
482
+ tostring_function -> scope = ce ;
483
+ tostring_function -> fn_flags = ZEND_ACC_PUBLIC |ZEND_ACC_HAS_RETURN_TYPE |ZEND_ACC_ARENA_ALLOCATED ;
484
+ tostring_function -> num_args = 0 ;
485
+ tostring_function -> required_num_args = 0 ;
486
+ tostring_function -> arg_info = (zend_internal_arg_info * ) (arginfo_class_Stringable___toString + 1 );
487
+ if (!zend_hash_add_ptr (
488
+ & ce -> function_table , ZSTR_KNOWN (ZEND_STR_TOSTRING_LOWERCASE ), tostring_function )) {
489
+ zend_error_noreturn (E_COMPILE_ERROR ,
490
+ "Cannot redeclare %s::__toString()" , ZSTR_VAL (ce -> name ));
491
+ }
492
+
493
+ ce -> __tostring = tostring_function ;
494
+ }
450
495
}
451
496
}
452
497
0 commit comments