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