@@ -1135,7 +1135,12 @@ static inheritance_status do_inheritance_check_on_method(
11351135
11361136#define SEPARATE_METHOD () do { \
11371137 if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1138- && child_scope != ce && child->type == ZEND_USER_FUNCTION) { \
1138+ && child_scope != ce \
1139+ /* Trait methods have already been separated at this point. However, their */ \
1140+ /* scope isn't fixed until after inheritance checks to preserve the scope */ \
1141+ /* in error messages. Skip them here explicitly. */ \
1142+ && !(child_scope -> ce_flags & ZEND_ACC_TRAIT ) \
1143+ && child -> type == ZEND_USER_FUNCTION ) { \
11391144 /* op_array wasn't duplicated yet */ \
11401145 zend_function * new_function = zend_arena_alloc (& CG (arena ), sizeof (zend_op_array )); \
11411146 memcpy (new_function , child , sizeof (zend_op_array )); \
@@ -2350,7 +2355,6 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
23502355{
23512356 zend_function * existing_fn = NULL ;
23522357 zend_function * new_fn ;
2353- bool check_inheritance = false;
23542358
23552359 if ((existing_fn = zend_hash_find_ptr (& ce -> function_table , key )) != NULL ) {
23562360 /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
@@ -2384,8 +2388,6 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
23842388 ZSTR_VAL (fn -> common .scope -> name ), ZSTR_VAL (fn -> common .function_name ),
23852389 ZSTR_VAL (ce -> name ), ZSTR_VAL (name ),
23862390 ZSTR_VAL (existing_fn -> common .scope -> name ), ZSTR_VAL (existing_fn -> common .function_name ));
2387- } else {
2388- check_inheritance = true;
23892391 }
23902392 }
23912393
@@ -2405,19 +2407,6 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
24052407 function_add_ref (new_fn );
24062408 fn = zend_hash_update_ptr (& ce -> function_table , key , new_fn );
24072409 zend_add_magic_method (ce , fn , key );
2408-
2409- if (check_inheritance ) {
2410- /* Inherited members are overridden by members inserted by traits.
2411- * Check whether the trait method fulfills the inheritance requirements. */
2412- uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY ;
2413- if (!(existing_fn -> common .scope -> ce_flags & ZEND_ACC_TRAIT )) {
2414- flags |= ZEND_INHERITANCE_SET_CHILD_CHANGED |ZEND_INHERITANCE_SET_CHILD_PROTO |
2415- ZEND_INHERITANCE_RESET_CHILD_OVERRIDE ;
2416- }
2417- do_inheritance_check_on_method (
2418- fn , fixup_trait_scope (fn , ce ), existing_fn , fixup_trait_scope (existing_fn , ce ),
2419- ce , NULL , flags );
2420- }
24212410}
24222411/* }}} */
24232412
@@ -2695,7 +2684,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
26952684}
26962685/* }}} */
26972686
2698- static void zend_do_traits_method_binding (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables , zend_class_entry * * aliases ) /* {{{ */
2687+ static void zend_do_traits_method_binding (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables , zend_class_entry * * aliases , bool verify_abstract , bool * contains_abstract_methods ) /* {{{ */
26992688{
27002689 uint32_t i ;
27012690 zend_string * key ;
@@ -2706,6 +2695,11 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
27062695 if (traits [i ]) {
27072696 /* copies functions, applies defined aliasing, and excludes unused trait methods */
27082697 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& traits [i ]-> function_table , key , fn ) {
2698+ bool is_abstract = (bool ) (fn -> common .fn_flags & ZEND_ACC_ABSTRACT );
2699+ * contains_abstract_methods |= is_abstract ;
2700+ if (verify_abstract != is_abstract ) {
2701+ continue ;
2702+ }
27092703 zend_traits_copy_functions (key , fn , ce , exclude_tables [i ], aliases );
27102704 } ZEND_HASH_FOREACH_END ();
27112705
@@ -2720,15 +2714,16 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
27202714 for (i = 0 ; i < ce -> num_traits ; i ++ ) {
27212715 if (traits [i ]) {
27222716 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& traits [i ]-> function_table , key , fn ) {
2717+ bool is_abstract = (bool ) (fn -> common .fn_flags & ZEND_ACC_ABSTRACT );
2718+ * contains_abstract_methods |= is_abstract ;
2719+ if (verify_abstract != is_abstract ) {
2720+ continue ;
2721+ }
27232722 zend_traits_copy_functions (key , fn , ce , NULL , aliases );
27242723 } ZEND_HASH_FOREACH_END ();
27252724 }
27262725 }
27272726 }
2728-
2729- ZEND_HASH_MAP_FOREACH_PTR (& ce -> function_table , fn ) {
2730- zend_fixup_trait_method (fn , ce );
2731- } ZEND_HASH_FOREACH_END ();
27322727}
27332728/* }}} */
27342729
@@ -3010,33 +3005,6 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent
30103005}
30113006/* }}} */
30123007
3013- static void zend_do_bind_traits (zend_class_entry * ce , zend_class_entry * * traits ) /* {{{ */
3014- {
3015- HashTable * * exclude_tables ;
3016- zend_class_entry * * aliases ;
3017-
3018- ZEND_ASSERT (ce -> num_traits > 0 );
3019-
3020- /* complete initialization of trait structures in ce */
3021- zend_traits_init_trait_structures (ce , traits , & exclude_tables , & aliases );
3022-
3023- /* first care about all methods to be flattened into the class */
3024- zend_do_traits_method_binding (ce , traits , exclude_tables , aliases );
3025-
3026- if (aliases ) {
3027- efree (aliases );
3028- }
3029-
3030- if (exclude_tables ) {
3031- efree (exclude_tables );
3032- }
3033-
3034- /* then flatten the constants and properties into it, to, mostly to notify developer about problems */
3035- zend_do_traits_constant_binding (ce , traits );
3036- zend_do_traits_property_binding (ce , traits );
3037- }
3038- /* }}} */
3039-
30403008#define MAX_ABSTRACT_INFO_CNT 3
30413009#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
30423010#define DISPLAY_ABSTRACT_FN (idx ) \
@@ -3649,14 +3617,45 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
36493617 zend_link_hooked_object_iter (ce );
36503618#endif
36513619
3620+ HashTable * * trait_exclude_tables ;
3621+ zend_class_entry * * trait_aliases ;
3622+ bool trait_contains_abstract_methods = false;
3623+ if (ce -> num_traits ) {
3624+ zend_traits_init_trait_structures (ce , traits_and_interfaces , & trait_exclude_tables , & trait_aliases );
3625+ zend_do_traits_method_binding (ce , traits_and_interfaces , trait_exclude_tables , trait_aliases , false, & trait_contains_abstract_methods );
3626+ zend_do_traits_constant_binding (ce , traits_and_interfaces );
3627+ zend_do_traits_property_binding (ce , traits_and_interfaces );
3628+ }
36523629 if (parent ) {
36533630 if (!(parent -> ce_flags & ZEND_ACC_LINKED )) {
36543631 add_dependency_obligation (ce , parent );
36553632 }
36563633 zend_do_inheritance (ce , parent );
36573634 }
36583635 if (ce -> num_traits ) {
3659- zend_do_bind_traits (ce , traits_and_interfaces );
3636+ if (trait_contains_abstract_methods ) {
3637+ zend_do_traits_method_binding (ce , traits_and_interfaces , trait_exclude_tables , trait_aliases , true, & trait_contains_abstract_methods );
3638+ }
3639+
3640+ if (trait_exclude_tables ) {
3641+ for (i = 0 ; i < ce -> num_traits ; i ++ ) {
3642+ if (traits_and_interfaces [i ]) {
3643+ if (trait_exclude_tables [i ]) {
3644+ zend_hash_destroy (trait_exclude_tables [i ]);
3645+ FREE_HASHTABLE (trait_exclude_tables [i ]);
3646+ }
3647+ }
3648+ }
3649+ efree (trait_exclude_tables );
3650+ }
3651+ if (trait_aliases ) {
3652+ efree (trait_aliases );
3653+ }
3654+
3655+ zend_function * fn ;
3656+ ZEND_HASH_MAP_FOREACH_PTR (& ce -> function_table , fn ) {
3657+ zend_fixup_trait_method (fn , ce );
3658+ } ZEND_HASH_FOREACH_END ();
36603659 }
36613660 if (ce -> num_interfaces ) {
36623661 /* Also copy the parent interfaces here, so we don't need to reallocate later. */
0 commit comments