144

Not a major problem but I was wondering if there is a cleaner way to do this. It would be good to avoid nesting my code with an unnecessary if statement. If $items is empty php throws an error.

$items = array('a','b','c');

if(!empty($items)) { // <-Remove this if statement
  foreach($items as $item) {
    print $item;
  }
}

I could probably just use the '@' error suppressor, but that would be a bit hacky.

Benbob
  • 13,876
  • 18
  • 79
  • 114
  • 20
    What? If you just comment out the `if` you have there, and change the first line to `$items = array();`, it works perfectly fine and operates logically. There must be more to your question. Is `$items` perhaps not an array? – strager Aug 10 '10 at 06:26
  • 2
    i guess its in case return from function which may return false too. I also have similar problem and i always check using is_array – KoolKabin Aug 10 '10 at 06:34
  • 2
    FYI - ``foreach does not support the ability to suppress error messages using '@'.` - http://php.net/manual/en/control-structures.foreach.php - so, no, you couldn't use `@` – Peter Ajtai Aug 10 '10 at 07:42
  • +1 for strager. If $items is really an array, php won't give you an error or warning. Check your if/else branches and make sure you initialized variable as an array. – csonuryilmaz Feb 25 '13 at 04:05
  • you can find this situation with data coming from a non-trusted function. That case, an if is not unnecessary and it can be even better/cleaner than some other solutions which could be more cryptic and harder to read. – Alejandro Moreno Oct 06 '14 at 15:49
  • How this is a duplicate of that question? This question is about code cleanliness, the other question is about resolving an error. – Flimm Jun 08 '17 at 16:31
  • Absurd duplicate answer flag. How can someone posibly find a clean way to do something (as asked) by looking for some random errors. Are they asking users to read the entire stackOverflow to notice mach? In any case the OTHER is related to this, but not otherwise. – Mbotet Jan 15 '20 at 12:36

11 Answers11

238

There are a million ways to do this.

The first one would be to go ahead and run the array through foreach anyway, assuming you do have an array.

In other cases this is what you might need:

foreach ((array) $items as $item) {
    print $item;
}

Note: to all the people complaining about typecast, please note that the OP asked cleanest way to skip a foreach if array is empty (emphasis is mine). A value of true, false, numbers or strings is not considered empty. In addition, this would work with objects implementing \Traversable, whereas is_array wouldn't work.

Christian
  • 27,509
  • 17
  • 111
  • 155
  • 2
    Just what I wanted. If the variable is not an array the loop won't be run. Thanks. – Benbob Aug 13 '10 at 03:53
  • 4
    @Keyo it would. and it will throw an error when $items undefined – Your Common Sense Oct 03 '11 at 11:51
  • @Keyo made an edit, describing what YCS means. Just don't do it generally ;) – nico gawenda Jul 04 '13 at 03:32
  • 9
    Notice,when $items is false.(array)$items will get array(false) – user890973 Jul 25 '13 at 06:29
  • I didn't get an error when $items undefined. Is this for the old version only? May be new PHP versions took care of this situation? – Binod Kalathil Apr 11 '14 at 14:48
  • But what if you want to show a message if array empty . – Sven van den Boogaart May 28 '14 at 22:30
  • @SvenB That's something else. Just do a `if (empty($items)) ...` – Christian May 29 '14 at 20:01
  • This is not clean and is likely to cause unexpected results. This is not a good practise. If you do `(array) false`, you will get an array with single element containing bool false. As `$items` is supposed to be an array, we should make sure it is an array; hence do the type juggling somewhere else. – Niklaus Oct 09 '18 at 05:31
  • @Niklaus you should have read the whole solution, including the last disclaimer that answers your point exactly (in particular, most people do not consider `false` as empty). If instead you had a `null` (which is considered empty), you'd get a warning without the typecast. – Christian Oct 09 '18 at 13:11
  • @Christian, In PHP `false` is empty. You can confirm this with `var_dump(empty(false));`. If we really want to avoid calling `foreach` with non-array, we should make sure `foreach` is getting an array (and we should know what kind of data is going into that array). If we only want to avoid `null`, we could do `foreach ($items ?? [] as $value)`, but I would not recommend that either. I would recommend checking the contents of `$items` before that loop, and maybe extracting that loop into a new method/function. That would solve the original nesting problem. – Niklaus Oct 10 '18 at 16:54
  • PHP's `empty` tends to be a false-y check rather than checking for true emptiness. Other than the terribly misnamed function, people wouldn't expect `false`, `0`, `'0'` etc as empty. `Null`, on the other hand is considered empty. But this whole argument is just nitpicking. The point here (which I've made clear above time and time again) is that if you have a value that can be an array, an empty array or a null, you can go ahead and typecast. Especially useful for `null|array` properties and `?array` arguments (esp with a default null value). – Christian Oct 10 '18 at 21:23
  • If you're looping through multidimensional associative array as of PHP 7.1 you can also do this: `foreach($items['data'] ?? [] as $item):` – Shreyansh Panchal Oct 11 '18 at 08:19
  • This doesn't work. eg ";} - http://sandbox.onlinephpfunctions.com/ – user2662680 Feb 06 '20 at 17:06
  • @user2662680 first of all, an *empty string* is not an *empty array*. Secondly, guess what? Your code works and simply does nothing: https://3v4l.org/imJjN – Christian Feb 07 '20 at 18:51
  • @Christian It is somewhat perverse to claim that `empty()` does not check whether a variable is empty. The definition of ‘empty’ within the scope of PHP is, “A variable is considered empty if it does not exist or if its value equals FALSE”. It doesn’t matter what people would expect or how other languages define emptiness (e.g., in VB6, null is _not_ considered empty) – in PHP, `FALSE`, `0` and `'0'` are all empty. Yes, typecasting is safe if the only possible options are array or null, but it does _not_ check for PHP emptiness. – Janus Bahs Jacquet Dec 15 '20 at 12:03
32

The best way is to initialize every bloody variable before use.
It will not only solve this silly "problem" but also save you a ton of real headaches.

So, introducing $items as $items = array(); is what you really wanted.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • 4
    Not if initializing from a function/method. `$items = get_stuff()`. It's easier just to cast and falsy variables return an empty array. – Benbob Oct 04 '11 at 22:41
  • 11
    `get_stuff()` may come from an external API. It's not uncommon for library functions to return `Array|NULL` – Frédéric Bolduc Apr 09 '16 at 17:40
  • 3
    Even phps own functions return different types. Assume you request some JSON array over the network. You know that the produced JSON is always an array. So json_decode() will always return an array? No. A network timeout might occur, the received JSON will be incomplete and json_decode will return NULL. This is not made up, its a real life example taken from a recent bug in piwik, a popular analytics script: https://github.com/piwik/piwik/pull/11098 From your answer, the solution would have been to change php's json_decode()? – Christopher K. Jan 17 '17 at 13:57
  • @ChristopherK. from my answer the solution is to validate your input. – Your Common Sense Jan 17 '17 at 14:05
  • 3
    @YourCommonSense where is your answer doing any validation? Validating would mean e.g. checking whether what json_decode() returned is an array, which is exactly what the answer of Matt Williamson says. – Christopher K. Jan 17 '17 at 14:13
  • @ChristopherK. this code you mention is a runtime crutch, that makes your code bloated. is_array should be used upon receive, not with output. And after the verification it should make $items = array(); if json returned null - just like it said in my answer – Your Common Sense Jan 17 '17 at 14:17
  • 1
    @YourCommonSense The solution you describe is of course correct. But your original answer does not mention that and how to validate the input. It might even lead some people to false assumptions, like thinking this is safe just because initialization was used: $items=array(); $items=json_decode($str); foreach($items as $item)... – Christopher K. Jan 17 '17 at 14:28
  • This actually make sense. I was getting error cause using $arr = []; but using array() foreach works – armin Aug 26 '20 at 05:37
30
$items = array('a','b','c');

if(is_array($items)) {
  foreach($items as $item) {
    print $item;
  }
}
Matt Williamson
  • 39,165
  • 10
  • 64
  • 72
  • 4
    This doesn't remove any lines, but the code is much more self documenting and easier to read. – Peter Ajtai Aug 10 '10 at 07:29
  • 5
    +1 this way if $items is array but is empty, the foreach will not run and there will be no error. but empty() doesn't guarantee if $items is an array, so an error is possible – Sergey Eremin Aug 10 '10 at 08:49
17

If variable you need could be boolean false - eg. when no records are returned from database or array - when records are returned, you can do following:

foreach (($result ? $result : array()) as $item)
    echo $item;

Approach with cast((Array)$result) produces an array of count 1 when variable is boolean false which isn't what you probably want.

Daniel Kmak
  • 18,164
  • 7
  • 66
  • 89
  • 2
    This will produce a syntax error when assigning by reference, as in "foreach... as &$item", because when $result is null it can't assign a reference to "array()". See: http://php.net/manual/en/control-structures.foreach.php – Russell G Feb 27 '15 at 19:48
  • Yes, good point. However, it is still useful in simpler cases. – Daniel Kmak Feb 27 '15 at 19:57
  • 2
    Since PHP 5.3, it is possible to leave out the middle part of the ternary operator. So it may become `foreach (($result ?: array()) as $item)`. And if `$result` may be `null`, then php 7 introduced `null coalescing operator` `foreach (($result ?? array()) as $item)`. See https://www.php.net/manual/en/language.operators.comparison.php – KumZ Aug 21 '20 at 13:04
17

I wouldn't recommend suppressing the warning output. I would, however, recommend using is_array instead of !empty. If $items happens to be a nonzero scalar, then the foreach will still error out if you use !empty.

Zach Rattner
  • 20,745
  • 9
  • 59
  • 82
  • 11
    +1 suppressing warnings and errors is **never** a good idea. – Christian Aug 10 '10 at 07:16
  • 3
    I hat the is_[array] function, this sound like a poor programming still. Let me explain why: Why asking that a variable is an array? You should know that is an array otherwise it mean that you are messing with the type of the variable. If your type is getting inconsistent you are looking for trouble. When you start using the is_* function it tend to be spread all over your code. And after all you never know if the is_* is necessary and your code is being unreadable. I suggest you to fix the origin of the type inconsistency instead. – mathk Aug 11 '10 at 09:42
  • 2
    @mathk You probably come from strongly typed language. PHP variable can store anything, that's why is_array, is_numeric, etc are needed functions. – Daniel Wu Nov 22 '19 at 05:41
6

I think the best approach here is to plan your code so that $items is always an array. The easiest solution is to initialize it at the top of your code with $items=array(). This way it will represent empty array even if you don't assign any value to it.

All other solutions are quite dirty hacks to me.

Vladislav Rastrusny
  • 29,378
  • 23
  • 95
  • 156
  • Sadly this doesn't work; PHP generates this error even when it's a properly empty array. It can't distinguish at runtime. – Chris Arguin Jun 05 '11 at 23:24
  • @Chris Arguin How come? Please post an example here. It shouldn't throw errors on array. – Vladislav Rastrusny Jun 06 '11 at 09:52
  • 1
    See http://snippetdb.com/php/foreach-empty-array for a simple example; I stumbled upon this article while trying to figure out why my PHP code was failing when they array was empty. This doesn't seem to happen to everybody, so there may be some complicating factor. – Chris Arguin Jun 10 '11 at 22:51
5
foreach((array)$items as $item) {}
Peter Ajtai
  • 56,972
  • 13
  • 121
  • 140
Milan
  • 173
  • 1
  • 1
  • 6
3

i've got the following function in my "standard library"

/// Convert argument to an array.
function a($a = null) {
    if(is_null($a))
        return array();
    if(is_array($a))
        return $a;
    if(is_object($a))
        return (array) $a;
    return $_ = func_get_args();
}

Basically, this does nothing with arrays/objects and convert other types to arrays. This is extremely handy to use with foreach statements and array functions

  foreach(a($whatever) as $item)....

  $foo = array_map(a($array_or_string)....

  etc
user187291
  • 53,363
  • 19
  • 95
  • 127
  • because you better ask why in first place you got a null or object instead of an array. You are assuming that the type is inconsistent. And you spread the test all over your code.That is kind of defensive programming. – mathk Aug 11 '10 at 12:09
1

You can check whether $items is actually an array and whether it contains any items:

if(is_array($items) && count($items) > 0)
{
    foreach($items as $item) { }
}
shasi kanth
  • 6,987
  • 24
  • 106
  • 158
  • 1
    count($items) > 0 is unnecessary, it is enough to check if $items is truthy -> empty arrays are falsy in PHP: if(is_array($items) && $items) – gsziszi May 04 '19 at 14:41
1

Ternary logic gets it down to one line with no errors. This solves the issue of improperly cast variables and undefined variables.

foreach (is_array($Items) || is_object($Items) ? $Items : array()  as $Item) {

It is a bit of a pain to write, but is the safest way to handle it.

swirt
  • 21
  • 2
0

Best practice is to define variable as an array at the very top of your code.

foreach((array)$myArr as $oneItem) { .. }

will also work but you will duplicate this (array) conversion everytime you need to loop through the array.

since it's important not to duplicate even a word of your code, you do better to define it as an empty array at top.

spetsnaz
  • 1,181
  • 1
  • 14
  • 11
  • This is not true. The typecasting is only done once. Also, PHP variables are not typed - a variable can change its type at any point in time. – Christian Sep 27 '15 at 02:14