DEV Community

Freek Van der Herten
Freek Van der Herten

Posted on • Originally published at freek.dev on

3 2

★ When empty is not empty

Recently when I was working on a project I got some strange results when using the empty function. Here's what I was debugging. I've simplified the code a bit to share with you.

var_dump(
   $person->firstName, 
   empty($person->firstName)
);

This was the result:

string(5) "Freek"
bool(true)

That's really odd. How can a variable hold a string and be empty at the same time? Let's try a few other functions on $person->firstName:

var_dump(
   $person->firstName, 
   empty($person->firstName), 
   isset($person->firstName), 
   is_null($person->firstName)
);

The result:

string(5) "Freek"
bool(true) // empty
bool(true) // isset
bool(false) // is_null

isset and is_null behave like expected, only empty returns the wrong result.

Let's take a look at the implementation of the Person class.

class Person
{
    protected $attributes = [];

    public function __construct(array $attributes)
    {
        $this->attributes = $attributes;
    }

    public function __get($name)
    {
        return $this->attributes[$name] ?? null;
    }
}

Here you can see that the properties on a Person object are retrieved from the $attributes array using that magic __get() method.

When passing variables to normal functions $person->firstName will be evaluated first. The result of that evaluation will get passed to the function.

But empty is not a function, it's a language construct. So what you pass to it will not be evaluated first. When passing $person->firstName to it, it will check the contents of the firstName property on $person. Since that property doesn't exist, it will return false.

If you want to make the empty function work in this case you'll need to implement the magic __isset method.

class Person
{
    protected $attributes = [];

    public function __construct(array $attributes)
    {
        $this->attributes = $attributes;
    }

    public function __get($name)
    {
        return $this->attributes[$name] ?? null;
    }

    public function __isset($name)
    {
        $attribute = $this->$name;

        return !empty($attribute);
    }
}

When empty does it's job it'll use that magic method to determine the result.

Let's try dumping again:

var_dump(
   $person->firstName, 
   empty($person->firstName)
);

The new results:

string(5) "Freek"
bool(false)

Perfect!

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay