DEV Community

Jimmy Klein
Jimmy Klein

Posted on • Edited on

Never use `empty` function in PHP

There are several ways to test that an array is empty in PHP, and the one I see most often is:

$var = [];

if (empty($var)) { ... }
Enter fullscreen mode Exit fullscreen mode

By reading the code, you immediately know what it does, the name of the function is quite self-explanatory. But the problem is the use of the empty function which is not only used to test array!

Did you know that using empty is like writing:

$var = [];

if (
    isset($var) === false
    || $var === false
    || $var === 0
    || $var === -0
    || $var === 0.0
    || $var === -0.0
    || $var === ''
    || $var === '0'
    || $var === []
) { ... }
Enter fullscreen mode Exit fullscreen mode

We can clearly see here that we can use empty to also test that an integer is equal to 0, or that a string is empty. And that's the problem with this function: it does too many things and can cause many bugs.

For example, a test with empty of an undeclared variable returns true without errors! So a bug can occur if you make a mistake in the name of your variable:

$var = [1, 2, 3];

var_dump(
    empty($errorVar)
); // bool(true)
Enter fullscreen mode Exit fullscreen mode

It is therefore better to test the expected value directly:

var_dump(
    $errorVar === []
); // bool(false)
/*
 * With php < 8 : Notice: Undefined variable: myErrorVar in /in/Nm3CT on line 8
 * With php >= 8 : Warning: Undefined variable $myErrorVar in /in/Nm3CT on line 8
 */
Enter fullscreen mode Exit fullscreen mode

What is the right method?

To test that an array is empty, I advise you to use one of the suggestions below instead.

$var = [];

if (count($var) === 0) {...}
// ou 
if (sizeof($var) === 0) {...}
Enter fullscreen mode Exit fullscreen mode

My favorite solution:

$var = [];

if ($var === []) {...}
Enter fullscreen mode Exit fullscreen mode

And more generally, I advise you to ban the empty function from your vocabulary and your daily life:

  • Want to test that an integer is equal to 0?
$var === 0
Enter fullscreen mode Exit fullscreen mode
  • Want to test that a string is empty?
$var === ''
Enter fullscreen mode Exit fullscreen mode
  • Do you want to test that a previously declared and initialized variable is equal to null?
$var = null;

if ($var === null) {...}
Enter fullscreen mode Exit fullscreen mode
  • If you want to test that a variable exists and is different from null, you must use the isset function
isset($var)
Enter fullscreen mode Exit fullscreen mode

It's simple, isn't it?


What if I want to test several things at the same time?

If for example, you want to test that your variable is not null and that it is not an empty string, you can either combine the two conditions:

if ($var !== null && $var !== '')
Enter fullscreen mode Exit fullscreen mode

Either create a private method with an explicit name which will do this control

private function isTokenValid(?string $token): bool
{
     return $token !== null && $token !== '';
}

// in the condition
if ($this->isTokenValid($var)) {...}
Enter fullscreen mode Exit fullscreen mode

Thank you for reading, and let's stay in touch !

If you liked this article, please share. Join me also on Twitter/X for more PHP tips.

Top comments (25)

Collapse
 
denis99455553 profile image
Denis
$var = [];
if ($var === []) {...}

Enter fullscreen mode Exit fullscreen mode

why not:

$var = [];
if (!$var) {...}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
klnjmm profile image
Jimmy Klein

You can.

It will force PHP to cast your variable in Boolean, which I want to avoid (for pretty the same reason to not use empty).

And I find it more explicit.

Collapse
 
gssj profile image
Guilherme dos Santos Souza Jรบnior

I find it kind of explicit that an empty array "means" false

Thread Thread
 
klnjmm profile image
Jimmy Klein

The problem is not that empty function returns false for an empty array, the problem is that empty function does to too many thing (not just on array).

Collapse
 
klnjmm profile image
Jimmy Klein

Thanks for your comment !

The problem is "There are some instances where empty works well.". In some case, it works well, but sometimes it cause a bug and you search after the root cause.

A lot of PHP beginners don't know how it works exactly and will have bugs because of the versatility of this function.

Many senior developers that I know prohibit the empty function, for the reasons that I explained.

It's just advice, then I'll let you do what you want ;)

Collapse
 
mykolahlushchenko95 profile image
MykolaHlushchenko95

A lot of PHP beginners don't know how works "if" or "for", so lets not use it...

Thread Thread
 
klnjmm profile image
Jimmy Klein

I have an other article for these beginners, who don't know how to make a loop : dev.to/klnjmm/never-write-another-... ๐Ÿคฃ

Collapse
 
danielhe4rt profile image
Daniel Reis

I agree. I do not want to do 3 different validations since it is there and always has a scenario to fit empty() in my codebase (don't ask me why).

I'd like to quote a famous singer who says important words regarding this statement:

Never say never - Justin Bieber.

Collapse
 
klnjmm profile image
Jimmy Klein

What is just "3 different validations" in order to avoid bugs ?

Thread Thread
 
chrisgalliano profile image
Christian Galliano • Edited

Sometimes you want to check if a variable is: 0, null, or "", and empty just makes this cleaner than doing isset and various other checks.

just cast to bool

if ((bool) $myVar) {  ... }
if (boolval($myVar)) {  ... }
Enter fullscreen mode Exit fullscreen mode

much more safe than empty & checks "", 0, null, false... etc. cases

Collapse
 
goodevilgenius profile image
Dan Jones • Edited
class Foo {
    public ?string $bar;
}

function getBar(Foo $f, string $default): string {
    return empty($f->bar) ? $default : $f->bar;
}
Enter fullscreen mode Exit fullscreen mode

This demonstrates a really good and safe way to use empty. In this case, we have a nullable string property. But, it could even be unset. In this case, getBar should return the default value if $f->bar is unset, null, or an empty string. This does exactly what it's supposed to do, and it's safe, because everything is typed. The only potential error here is the case of a typo, and that's what tools like phpstan (or your own IDE) are for.

Collapse
 
goodevilgenius profile image
Dan Jones

In case it wasn't obvious, the alternative would be:

function getBar(Foo $f, string $default): string {
  if (!isset($f->bar) || is_null($f->bar) || $f->bar === '') {
    return $default;
  }
  return $f->bar;
}
Enter fullscreen mode Exit fullscreen mode

You can't tell me that's better code.

Collapse
 
klnjmm profile image
Jimmy Klein

It is a lot of combination that make the use of empty safe.

For you second example, isset method test that the value is not null.

So itโ€™s just

if (!isset($f->bar) || $f->bar === '')
Enter fullscreen mode Exit fullscreen mode

Not so dirty ๐Ÿ˜‰

Thread Thread
 
goodevilgenius profile image
Dan Jones

I had forgotten that isset stupidly returns false for null values.

Yes, not quite so bad, but I still prefer empty in this case.

Thread Thread
 
timw4mail profile image
Timothy Warren

Ah yes, the annoying case where an explicit null value is different from an unset value. But if you have an object or array where you need to see if a property exists, this can be quite useful.

For objects/classes where you don't need the distinction, property_exists is the function you want.

This is one of those weird edge cases in dynamic programming languages. For the most part, I'll take the unset vs explicit null in PHP over the undefined/null split in Javascript.

Collapse
 
alesrosa profile image
Alessandro Rosa • Edited

Some months ago, I sent a proposal to php.dev for updating the empty function, because of internal flaws and semantic inconsistence. The new version I named is_empty_obj fixes all above.

Collapse
 
mexikode profile image
MexiKode โš™ • Edited

Then roll your own!

$ble = 0;
function is_empty($var){
if (isset($var) === false  || $var === false  || $var === null  || $var === -0.0  || $var === ''  || $var === [])
return true; 
return false;
}

echo is_empty($ble) ? "Empty" :"Not Empty: $ble";
Enter fullscreen mode Exit fullscreen mode
Collapse
 
krabyoto profile image
krabyoto • Edited

When we talk about clean & readable code, we try to avoid large comparisons. So empty() function help us in that journey. I know itยดs not perfect because it canยดt eval objects in the same way, so if you donยดt want to be thinking when use it or not, instead eval two or three differents options, you can use your own Empty function, extending it in some core class or redefining with runkit7_function_redefine (I prefer first option).

Something like:

function newEmpty(string|int|float|bool|array|object $var = 0): bool
{
    if(is_object($var)) {
        $var = (array) $var;
    }   
    return empty($var);
}
Enter fullscreen mode Exit fullscreen mode

If you want to try:

$array = [];
$object = new StdClass(); 
$string = "";
$number = 0.0;

echo "array " . (newEmpty($array) ? "" : "NOT ") . "empty \n";
echo "object " . (newEmpty($object) ? "" : "NOT ") . "empty \n";
echo "string " . (newEmpty($string) ? "" :  "NOT ") . "empty \n";
echo "number " . (newEmpty($number) ? " " : "NOT ") . "empty \n";
Enter fullscreen mode Exit fullscreen mode
Collapse
 
klnjmm profile image
Jimmy Klein

empty function is FOR ME not ยซย clean codeย ยป. Itโ€™s not a matter of comparing object, itโ€™s because it tests too much thing and that can cause bugs.
Like I describe in the article, if you find your comparaison too ยซย bigย ยป, you can extract it in a method with a understandable name.

If you have to compare object, I think you can do it otherwise.

And for you, what is an ยซย emptyย ยป object ? A object with all attributes equal to null ?

Collapse
 
lito profile image
Lito

I love the empty function!

Collapse
 
klnjmm profile image
Jimmy Klein

๐Ÿ˜†๐Ÿคฃ

Collapse
 
cephalicmarble profile image
Archie Campbell • Edited
<?php
class foo {
    public ?string $bar;
    public function __construct( $bar = null) {
        $this->bar = $bar;
        $this->message = 'look out';
        $this->default = 'hello, world';
    }
    protected function bardef() :string {
        return $this->bar ?? $this->default;
    }
    public function baz() :string {
        switch ( array_map(
                function( $i ) {
                    return ($i[0] ?? "\0") <=> ($i ?? "\0");
                },
                isset( $this->bar ) ? str_split( $this->bar ) : [ $this->bar ]
                )[0] ?? -1 ) {
            case 1:
                return $this->default;
            case -1:
                return $this->message;
            default:
                return empty($choice = $this->bardef()) ? $this->message : $choice;
        }
    }
}
echo (new foo())->baz() . "\n";
echo (new foo(''))->baz() . "\n";
echo (new foo('blargle'))->baz() . "\n";
foreach( array_merge( range( ord('a'), ord('z') ), range( ord('A'), ord('Z') ) ) as $c ) {
    echo (new foo(chr($c)))->baz() . "\n";
}
Enter fullscreen mode Exit fullscreen mode

I spent waaay too long trying to mirror the discussion.
I really hope this turns up in a technical interview someplace, somewhen.

Collapse
 
zullkas profile image
Radu Aftinescu

I disagree. You should understand what you're doing and use the proper functions for each case. The empty isn't bad.
As an argument: someone will copy your "right method" if (count($var) === 0) {...} as a "silver bullet" and apply it to an array with thousands of elements (because Jimmy said that's the solution). It will cause huge performance issues.

Collapse
 
klnjmm profile image
Jimmy Klein

Thanks for your reply.
Maybe Iโ€™m wrong, but count on a large array is not slower than count on a small array. The size of an array is stored internally, PHP does not count the number of items each time you call the function.