@@ -3617,7 +3617,19 @@ static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args
3617
3617
/* if it is an abstract method, there is no collision */
3618
3618
if (other_trait_fn -> common .fn_flags & ZEND_ACC_ABSTRACT ) {
3619
3619
/* Make sure they are compatible */
3620
- do_inheritance_check_on_method (fn , other_trait_fn TSRMLS_CC );
3620
+ if (fn -> common .fn_flags & ZEND_ACC_ABSTRACT ) {
3621
+ /* In case both are abstract, just check prototype, but need to do that in both directions */
3622
+ if ( !zend_do_perform_implementation_check (fn , other_trait_fn TSRMLS_CC )
3623
+ || !zend_do_perform_implementation_check (other_trait_fn , fn TSRMLS_CC )) {
3624
+ zend_error (E_COMPILE_ERROR , "Declaration of %s must be compatible with %s" , //ZEND_FN_SCOPE_NAME(fn), fn->common.function_name, //::%s()
3625
+ zend_get_function_declaration (fn TSRMLS_CC ),
3626
+ zend_get_function_declaration (other_trait_fn TSRMLS_CC ));
3627
+ }
3628
+ }
3629
+ else {
3630
+ /* otherwise, do the full check */
3631
+ do_inheritance_check_on_method (fn , other_trait_fn TSRMLS_CC );
3632
+ }
3621
3633
3622
3634
/* we can savely free and remove it from other table */
3623
3635
zend_function_dtor (other_trait_fn );
@@ -3626,7 +3638,8 @@ static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args
3626
3638
/* if it is not an abstract method, there is still no collision */
3627
3639
/* if fn is an abstract method */
3628
3640
if (fn -> common .fn_flags & ZEND_ACC_ABSTRACT ) {
3629
- /* Make sure they are compatible */
3641
+ /* Make sure they are compatible.
3642
+ Here, we already know other_trait_fn cannot be abstract, full check ok. */
3630
3643
do_inheritance_check_on_method (other_trait_fn , fn TSRMLS_CC );
3631
3644
3632
3645
/* just mark as solved, will be added if its own trait is processed */
@@ -3843,39 +3856,39 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int
3843
3856
zend_function * existing_fn = NULL ;
3844
3857
zend_function fn_copy , * fn_copy_p ;
3845
3858
zend_function * prototype = NULL ; /* is used to determine the prototype according to the inheritance chain */
3846
-
3859
+
3847
3860
if (zend_hash_quick_find (& ce -> function_table , hash_key -> arKey , hash_key -> nKeyLength , hash_key -> h , (void * * ) & existing_fn ) == FAILURE ) {
3848
3861
add = 1 ; /* not found */
3849
3862
} else if (existing_fn -> common .scope != ce ) {
3850
3863
add = 1 ; /* or inherited from other class or interface */
3851
3864
}
3852
-
3865
+
3853
3866
if (add ) {
3854
3867
zend_function * parent_function ;
3855
3868
if (ce -> parent && zend_hash_quick_find (& ce -> parent -> function_table , hash_key -> arKey , hash_key -> nKeyLength , hash_key -> h , (void * * ) & parent_function ) != FAILURE ) {
3856
3869
prototype = parent_function ; /* ->common.fn_flags |= ZEND_ACC_ABSTRACT; */
3857
3870
3858
3871
/* we got that method in the parent class, and are going to override it,
3859
- except, if the trait is just asking to have an abstract method implemented. */
3872
+ except, if the trait is just asking to have an abstract method implemented. */
3860
3873
if (fn -> common .fn_flags & ZEND_ACC_ABSTRACT ) {
3861
3874
/* then we clean up an skip this method */
3862
3875
zend_function_dtor (fn );
3863
3876
return ZEND_HASH_APPLY_REMOVE ;
3864
3877
}
3865
3878
}
3866
-
3879
+
3867
3880
fn -> common .scope = ce ;
3868
3881
fn -> common .prototype = prototype ;
3869
-
3882
+
3870
3883
if (prototype
3871
- && (prototype -> common .fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT
3872
- || prototype -> common .fn_flags & ZEND_ACC_ABSTRACT )) {
3873
- fn -> common .fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT ;
3874
- } else if (fn -> common .fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT ) {
3875
- /* remove ZEND_ACC_IMPLEMENTED_ABSTRACT flag, think it shouldn't be copied to class */
3876
- fn -> common .fn_flags = fn -> common .fn_flags - ZEND_ACC_IMPLEMENTED_ABSTRACT ;
3877
- }
3878
-
3884
+ && (prototype -> common .fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT
3885
+ || prototype -> common .fn_flags & ZEND_ACC_ABSTRACT )) {
3886
+ fn -> common .fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT ;
3887
+ } else if (fn -> common .fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT ) {
3888
+ /* remove ZEND_ACC_IMPLEMENTED_ABSTRACT flag, think it shouldn't be copied to class */
3889
+ fn -> common .fn_flags = fn -> common .fn_flags - ZEND_ACC_IMPLEMENTED_ABSTRACT ;
3890
+ }
3891
+
3879
3892
/* check whether the trait method fullfills the inheritance requirements */
3880
3893
if (prototype ) {
3881
3894
do_inheritance_check_on_method (fn , prototype TSRMLS_CC );
@@ -3906,18 +3919,18 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int
3906
3919
}
3907
3920
fn_copy = * fn ;
3908
3921
zend_traits_duplicate_function (& fn_copy , ce , estrdup (fn -> common .function_name ) TSRMLS_CC );
3909
-
3922
+
3910
3923
if (zend_hash_quick_update (& ce -> function_table , hash_key -> arKey , hash_key -> nKeyLength , hash_key -> h , & fn_copy , sizeof (zend_function ), (void * * )& fn_copy_p )== FAILURE ) {
3911
3924
zend_error (E_COMPILE_ERROR , "Trait method %s has not been applied, because failure occured during updating class method table" , hash_key -> arKey );
3912
3925
}
3913
-
3926
+
3914
3927
zend_add_magic_methods (ce , hash_key -> arKey , hash_key -> nKeyLength , fn_copy_p TSRMLS_CC );
3915
-
3928
+
3916
3929
zend_function_dtor (fn );
3917
3930
} else {
3918
3931
zend_function_dtor (fn );
3919
3932
}
3920
-
3933
+
3921
3934
return ZEND_HASH_APPLY_REMOVE ;
3922
3935
}
3923
3936
/* }}} */
0 commit comments