@@ -2683,6 +2683,69 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
26832683}
26842684/* }}} */
26852685
2686+ static void zend_traits_check_for_mutual_exclusions (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables ) /* {{{ */
2687+ {
2688+ uint32_t i ;
2689+ zend_string * key ;
2690+ zend_function * fn ;
2691+ HashTable * all_method_sources ;
2692+ zend_class_entry * trait ;
2693+ (void ) trait ; /* Silence unused variable warning */
2694+
2695+ ALLOC_HASHTABLE (all_method_sources );
2696+ zend_hash_init (all_method_sources , 0 , NULL , NULL , 0 );
2697+
2698+ for (i = 0 ; i < ce -> num_traits ; i ++ ) {
2699+ if (!traits [i ]) {
2700+ continue ;
2701+ }
2702+
2703+ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& traits [i ]-> function_table , key , fn ) {
2704+ HashTable * sources ;
2705+
2706+ if ((sources = zend_hash_find_ptr (all_method_sources , key )) == NULL ) {
2707+ ALLOC_HASHTABLE (sources );
2708+ zend_hash_init (sources , 0 , NULL , NULL , 0 );
2709+ zend_hash_add_ptr (all_method_sources , key , sources );
2710+ }
2711+
2712+ zend_hash_index_add_ptr (sources , i , traits [i ]);
2713+ } ZEND_HASH_FOREACH_END ();
2714+ }
2715+
2716+ /* Are all method implementations excluded? */
2717+ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (all_method_sources , key , fn ) {
2718+ HashTable * sources = (HashTable * )fn ;
2719+ bool has_available_impl = false;
2720+ uint32_t trait_index ;
2721+
2722+ ZEND_HASH_FOREACH_NUM_KEY_PTR (sources , trait_index , trait ) {
2723+ /* Trait's implementation is excluded? */
2724+ if (!exclude_tables [trait_index ] ||
2725+ zend_hash_find (exclude_tables [trait_index ], key ) == NULL ) {
2726+ has_available_impl = true;
2727+ break ;
2728+ }
2729+ } ZEND_HASH_FOREACH_END ();
2730+
2731+ if (!has_available_impl && zend_hash_num_elements (sources ) > 1 ) {
2732+ zend_error_noreturn (E_COMPILE_ERROR ,
2733+ "Invalid trait method precedence for %s() - all implementations have been excluded by insteadof rules" ,
2734+ ZSTR_VAL (key ));
2735+ }
2736+ } ZEND_HASH_FOREACH_END ();
2737+
2738+ ZEND_HASH_MAP_FOREACH_PTR (all_method_sources , fn ) {
2739+ HashTable * sources = (HashTable * )fn ;
2740+ zend_hash_destroy (sources );
2741+ FREE_HASHTABLE (sources );
2742+ } ZEND_HASH_FOREACH_END ();
2743+
2744+ zend_hash_destroy (all_method_sources );
2745+ FREE_HASHTABLE (all_method_sources );
2746+ }
2747+ /* }}} */
2748+
26862749static void zend_do_traits_method_binding (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables , zend_class_entry * * aliases ) /* {{{ */
26872750{
26882751 uint32_t i ;
@@ -3009,6 +3072,10 @@ static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits)
30093072 /* complete initialization of trait structures in ce */
30103073 zend_traits_init_trait_structures (ce , traits , & exclude_tables , & aliases );
30113074
3075+ if (exclude_tables ) {
3076+ zend_traits_check_for_mutual_exclusions (ce , traits , exclude_tables );
3077+ }
3078+
30123079 /* first care about all methods to be flattened into the class */
30133080 zend_do_traits_method_binding (ce , traits , exclude_tables , aliases );
30143081
0 commit comments