> The more angles we approach this, the more it looks like generics, or at > least the same basis.
Which is well outside the scope of what I'd like to see, so let's look at form 2 in closer detail - the all functions. bool all_array( mixed $var ) { if (is_iterable($var) && !is_callable) { foreach ($var as $v) { if (!is_array($v)) return false; } return true; } return false; } That is the base function signature and implementation. The is_callable() above prevents iteration over generators, potentially consuming them for no purpose. The other functions in the family and their single value equivalents are: is_bool -> all_bool is_callable -> all_callable is_double -> all_double is_float -> all_float is_int -> all_int is_iterable -> all_iterable is_long -> all_long is_null -> all_null is_numeric -> all_numeric is_object -> all_object is_real -> all_real is_resource -> all_resource is_scalar -> all_scalar is_string -> all_string is_subclass_of -> all_are On the last one - is_subclass_of is generally more useful than is_a, but will doing this cause confusion? Also, not all of these need to be included - the above is a list of candidate functions to create. Of all of these all_string() would probably see the most use followed by all_numeric(). This will give the tools to do the desired assertions in a clean, easy to read manner. Collections that must be of a single iterable class can also be verified: assert($a instanceof \SomeClass && all_string($a)); But most of the time $a will merely be an array.