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