@@ -2306,6 +2306,69 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
23062306}
23072307/* }}} */
23082308
2309+ static void zend_traits_check_for_mutual_exclusions (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables ) /* {{{ */
2310+ {
2311+ uint32_t i ;
2312+ zend_string * key ;
2313+ zend_function * fn ;
2314+ HashTable * all_method_sources ;
2315+ zend_class_entry * trait ;
2316+ (void ) trait ; /* Silence unused variable warning */
2317+
2318+ ALLOC_HASHTABLE (all_method_sources );
2319+ zend_hash_init (all_method_sources , 0 , NULL , NULL , 0 );
2320+
2321+ for (i = 0 ; i < ce -> num_traits ; i ++ ) {
2322+ if (!traits [i ]) {
2323+ continue ;
2324+ }
2325+
2326+ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& traits [i ]-> function_table , key , fn ) {
2327+ HashTable * sources ;
2328+
2329+ if ((sources = zend_hash_find_ptr (all_method_sources , key )) == NULL ) {
2330+ ALLOC_HASHTABLE (sources );
2331+ zend_hash_init (sources , 0 , NULL , NULL , 0 );
2332+ zend_hash_add_ptr (all_method_sources , key , sources );
2333+ }
2334+
2335+ zend_hash_index_add_ptr (sources , i , traits [i ]);
2336+ } ZEND_HASH_FOREACH_END ();
2337+ }
2338+
2339+ /* Are all method implementations excluded? */
2340+ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (all_method_sources , key , fn ) {
2341+ HashTable * sources = (HashTable * )fn ;
2342+ bool has_available_impl = false;
2343+ uint32_t trait_index ;
2344+
2345+ ZEND_HASH_FOREACH_NUM_KEY_PTR (sources , trait_index , trait ) {
2346+ /* Trait's implementation is excluded? */
2347+ if (!exclude_tables [trait_index ] ||
2348+ zend_hash_find (exclude_tables [trait_index ], key ) == NULL ) {
2349+ has_available_impl = true;
2350+ break ;
2351+ }
2352+ } ZEND_HASH_FOREACH_END ();
2353+
2354+ if (!has_available_impl && zend_hash_num_elements (sources ) > 1 ) {
2355+ zend_error_noreturn (E_COMPILE_ERROR ,
2356+ "Invalid trait method precedence for %s() - all implementations have been excluded by insteadof rules" ,
2357+ ZSTR_VAL (key ));
2358+ }
2359+ } ZEND_HASH_FOREACH_END ();
2360+
2361+ ZEND_HASH_MAP_FOREACH_PTR (all_method_sources , fn ) {
2362+ HashTable * sources = (HashTable * )fn ;
2363+ zend_hash_destroy (sources );
2364+ FREE_HASHTABLE (sources );
2365+ } ZEND_HASH_FOREACH_END ();
2366+
2367+ zend_hash_destroy (all_method_sources );
2368+ FREE_HASHTABLE (all_method_sources );
2369+ }
2370+ /* }}} */
2371+
23092372static void zend_do_traits_method_binding (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables , zend_class_entry * * aliases ) /* {{{ */
23102373{
23112374 uint32_t i ;
@@ -2591,6 +2654,10 @@ static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits)
25912654 /* complete initialization of trait structures in ce */
25922655 zend_traits_init_trait_structures (ce , traits , & exclude_tables , & aliases );
25932656
2657+ if (exclude_tables ) {
2658+ zend_traits_check_for_mutual_exclusions (ce , traits , exclude_tables );
2659+ }
2660+
25942661 /* first care about all methods to be flattened into the class */
25952662 zend_do_traits_method_binding (ce , traits , exclude_tables , aliases );
25962663
0 commit comments