@@ -2304,6 +2304,67 @@ 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+ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& traits [i ]-> function_table , key , fn ) {
2322+ HashTable * sources ;
2323+
2324+ if ((sources = zend_hash_find_ptr (all_method_sources , key )) == NULL ) {
2325+ ALLOC_HASHTABLE (sources );
2326+ zend_hash_init (sources , 0 , NULL , NULL , 0 );
2327+ zend_hash_add_ptr (all_method_sources , key , sources );
2328+ }
2329+
2330+ zend_hash_index_add_ptr (sources , i , traits [i ]);
2331+ } ZEND_HASH_FOREACH_END ();
2332+ }
2333+ }
2334+
2335+ /* Are all method implementations excluded? */
2336+ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (all_method_sources , key , fn ) {
2337+ HashTable * sources = (HashTable * )fn ;
2338+ bool has_available_impl = false;
2339+ uint32_t trait_index ;
2340+
2341+ ZEND_HASH_FOREACH_NUM_KEY_PTR (sources , trait_index , trait ) {
2342+ /* Trait's implementation is excluded? */
2343+ if (!exclude_tables [trait_index ] ||
2344+ zend_hash_find (exclude_tables [trait_index ], key ) == NULL ) {
2345+ has_available_impl = true;
2346+ break ;
2347+ }
2348+ } ZEND_HASH_FOREACH_END ();
2349+
2350+ if (!has_available_impl && zend_hash_num_elements (sources ) > 1 ) {
2351+ zend_error_noreturn (E_COMPILE_ERROR ,
2352+ "Invalid trait method precedence for %s() - all implementations have been excluded by insteadof rules" ,
2353+ ZSTR_VAL (key ));
2354+ }
2355+ } ZEND_HASH_FOREACH_END ();
2356+
2357+ ZEND_HASH_MAP_FOREACH_PTR (all_method_sources , fn ) {
2358+ HashTable * sources = (HashTable * )fn ;
2359+ zend_hash_destroy (sources );
2360+ FREE_HASHTABLE (sources );
2361+ } ZEND_HASH_FOREACH_END ();
2362+
2363+ zend_hash_destroy (all_method_sources );
2364+ FREE_HASHTABLE (all_method_sources );
2365+ }
2366+ /* }}} */
2367+
23072368static void zend_do_traits_method_binding (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables , zend_class_entry * * aliases ) /* {{{ */
23082369{
23092370 uint32_t i ;
@@ -2589,6 +2650,10 @@ static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits)
25892650 /* complete initialization of trait structures in ce */
25902651 zend_traits_init_trait_structures (ce , traits , & exclude_tables , & aliases );
25912652
2653+ if (exclude_tables ) {
2654+ zend_traits_check_for_mutual_exclusions (ce , traits , exclude_tables );
2655+ }
2656+
25922657 /* first care about all methods to be flattened into the class */
25932658 zend_do_traits_method_binding (ce , traits , exclude_tables , aliases );
25942659
0 commit comments