什么是验证元素是否已准备好在php中的foreach()循环中使用的最佳方法?

example:

foreach($boxes as $box) {
    echo "$box 
";
}

Used to be fairly easy, I could just wrap the foreach around a check like:

if(is_array($boxes) && count($boxes) > 0) {
    //foreach loop here
}

Without having to worry about a warning getting thrown if for whatever reason bad input was passed to the $boxes array.

When Iterators, were added to the mix, this no longer works, as Iteratable objects are not arrays. So, I have a few solutions, but am wondering if there is a 'best practice' for this.

// 1:
if($boxes instanceof Traversable && count($boxes) > 0) {
    //foreach loop here
}

// 2:
if($boxes && count($boxes) > 0) {
    //foreach loops here
}

There are others, but these seem like the most obvious. Anyone have any suggestions. PHP docs seem to be silent.

You shouldn't have the count($array) > 0 part, because a) foreach works fine with empty arrays, b) objects can be Traversable yet not be Countable and c) the value returned by count() may even (for objects) be disconnected from the number of items the traversal will yield.

And #1 there is different from #2; since $boxes instanceOf Traversable is not the same as $boxes. Also note that internally arrays don't implement Traversable.

I would go with

if (is_array($boxes) || $boxes instanceof Traversable) {
    foreach (...)
}

This still doesn't guarantee that the traversal will be successful; the iteration may throw an exception at any point. In particular, for some classes it may not make sense to traverse them more than once.

I think generally in these cases you would probably know that the variable is going to be iterable if it is not null or false etc., so I would be happy to just do:

if ($boxes) {
    foreach ($boxes as $box) {}
}

Maybe that is naive though

One possibility depending on your php version is a cast:

<?php

$a = array('foo', array('bar'));

foreach ($a as $thing)
  foreach ((array) $thing as $item) // <-- here
    echo "$item
";
?>

This test will give true for both arrays and array-like objects

if (is_array($obj) || $obj instanceof Traversable) {
    foreach ($obj as $item) { /* foreach loop is safe here */
    }
}

In PHP5 you can iterate over any array or object so..

if (is_array($my_var) || is_object($my_var)) {
    // Do some foreachin'
}