DEV Community

Never use `empty` function in PHP

Jimmy Klein on February 19, 2024

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...
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.

Collapse
 
alesrosa profile image
Alessandro Rosa • Edited

I implemented this function to check "emptiness" for different variable types.
It is part of my libs since the last Fall. It works like a charm.
I replaced any call to standard empty() function.

function is_empty_obj( $input = null )
{
    $ser = @serialize( $input );
    if ( preg_match( "/^N;$/i", $ser ) === 1 ) return 1;
    if ( preg_match( "/^b\:[01]\;?$/i", $ser ) === 1 ) return 1;
    return preg_match( "/0\:(\{\}|\[\]|\"\")\;?$/i", $ser ) === 1 ? 1 : 0;
}
Enter fullscreen mode Exit fullscreen mode