Ok, here's another idea I've been mulling over. This I know is possible because I've done it using user land code, specifically Drupal 8's Assertion\Inspector class.
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Assertion%21Inspector.php/class/Inspector/8.5.x These methods provide a means to inspect collections - arrays usually but also Traversables. They fill a hole in the PHP library - the ability to check collection integrity. To answer the question "Why in core?" - well, Drupal needing to do this using a library referenced only by assert() statements creates an undocumented dependency for any class that wants to run these checks. From a pragmatic standpoint it just feels wrong. Most other languages have some means of doing these checks. IMPLEMENTATION STYLE #1: collectionof operator The style of implementation I like the most is a collectionof operator in parallel to the instance_of operator. It would be instanceof's plural brother, so $arg collectionof \SomeClass To pass the check $arg must be of the iterable psuedotype with all its values being a \SomeClass object. This is all well and good, but collection integrity checks are usually going to be looking to see if all the members are the same scalar. $arg collectionof string For language consistency we would need to allow instance_of to do the same, which it currently does not. $arg instanceof string This does create duplication with the is_* family of functions, but instanceof already overlaps is_a heavily. IMPLEMENTATION STYLE #2: all_* This style takes the is_* family and creates plural cousins for them. Example: all_string($arg); This is most similar to the user land solution. Following the current is_* family this gives us all_array(), all_bool(), all_callable(), all_double(), all_float(), all_int(), all_integer(), all_iterable(), all_long(), all_null(), all_numeric(), all_object(), all_real(), all_scalar(), and all_string(). One other function, all_are(), would be necessary for class and interface inspection. That's a lot of new functions, and the chance of BC breaking with someone's code is very high, so I don't personally like this approach. I'm putting it out there as alternate because despite that shortcoming it is a sensible alternative.