@@ -2304,6 +2304,69 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
2304
2304
}
2305
2305
/* }}} */
2306
2306
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
+
2307
2370
static void zend_do_traits_method_binding (zend_class_entry * ce , zend_class_entry * * traits , HashTable * * exclude_tables , zend_class_entry * * aliases ) /* {{{ */
2308
2371
{
2309
2372
uint32_t i ;
@@ -2589,6 +2652,10 @@ static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits)
2589
2652
/* complete initialization of trait structures in ce */
2590
2653
zend_traits_init_trait_structures (ce , traits , & exclude_tables , & aliases );
2591
2654
2655
+ if (exclude_tables ) {
2656
+ zend_traits_check_for_mutual_exclusions (ce , traits , exclude_tables );
2657
+ }
2658
+
2592
2659
/* first care about all methods to be flattened into the class */
2593
2660
zend_do_traits_method_binding (ce , traits , exclude_tables , aliases );
2594
2661
0 commit comments