@@ -1135,7 +1135,12 @@ static inheritance_status do_inheritance_check_on_method(
1135
1135
1136
1136
#define SEPARATE_METHOD () do { \
1137
1137
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 ) { \
1139
1144
/* op_array wasn't duplicated yet */ \
1140
1145
zend_function * new_function = zend_arena_alloc (& CG (arena ), sizeof (zend_op_array )); \
1141
1146
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_
2350
2355
{
2351
2356
zend_function * existing_fn = NULL ;
2352
2357
zend_function * new_fn ;
2353
- bool check_inheritance = false;
2354
2358
2355
2359
if ((existing_fn = zend_hash_find_ptr (& ce -> function_table , key )) != NULL ) {
2356
2360
/* 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_
2384
2388
ZSTR_VAL (fn -> common .scope -> name ), ZSTR_VAL (fn -> common .function_name ),
2385
2389
ZSTR_VAL (ce -> name ), ZSTR_VAL (name ),
2386
2390
ZSTR_VAL (existing_fn -> common .scope -> name ), ZSTR_VAL (existing_fn -> common .function_name ));
2387
- } else {
2388
- check_inheritance = true;
2389
2391
}
2390
2392
}
2391
2393
@@ -2405,19 +2407,6 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
2405
2407
function_add_ref (new_fn );
2406
2408
fn = zend_hash_update_ptr (& ce -> function_table , key , new_fn );
2407
2409
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
- }
2421
2410
}
2422
2411
/* }}} */
2423
2412
@@ -2695,7 +2684,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
2695
2684
}
2696
2685
/* }}} */
2697
2686
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 ) /* {{{ */
2699
2688
{
2700
2689
uint32_t i ;
2701
2690
zend_string * key ;
@@ -2706,6 +2695,11 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
2706
2695
if (traits [i ]) {
2707
2696
/* copies functions, applies defined aliasing, and excludes unused trait methods */
2708
2697
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
+ }
2709
2703
zend_traits_copy_functions (key , fn , ce , exclude_tables [i ], aliases );
2710
2704
} ZEND_HASH_FOREACH_END ();
2711
2705
@@ -2720,15 +2714,16 @@ static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry
2720
2714
for (i = 0 ; i < ce -> num_traits ; i ++ ) {
2721
2715
if (traits [i ]) {
2722
2716
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
+ }
2723
2722
zend_traits_copy_functions (key , fn , ce , NULL , aliases );
2724
2723
} ZEND_HASH_FOREACH_END ();
2725
2724
}
2726
2725
}
2727
2726
}
2728
-
2729
- ZEND_HASH_MAP_FOREACH_PTR (& ce -> function_table , fn ) {
2730
- zend_fixup_trait_method (fn , ce );
2731
- } ZEND_HASH_FOREACH_END ();
2732
2727
}
2733
2728
/* }}} */
2734
2729
@@ -3010,33 +3005,6 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent
3010
3005
}
3011
3006
/* }}} */
3012
3007
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
-
3040
3008
#define MAX_ABSTRACT_INFO_CNT 3
3041
3009
#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
3042
3010
#define DISPLAY_ABSTRACT_FN (idx ) \
@@ -3649,14 +3617,45 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
3649
3617
zend_link_hooked_object_iter (ce );
3650
3618
#endif
3651
3619
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
+ }
3652
3629
if (parent ) {
3653
3630
if (!(parent -> ce_flags & ZEND_ACC_LINKED )) {
3654
3631
add_dependency_obligation (ce , parent );
3655
3632
}
3656
3633
zend_do_inheritance (ce , parent );
3657
3634
}
3658
3635
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 ();
3660
3659
}
3661
3660
if (ce -> num_interfaces ) {
3662
3661
/* Also copy the parent interfaces here, so we don't need to reallocate later. */
0 commit comments