Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

When empty is not empty

Original – by Freek Van der Herten – 2 minute read

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!

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

What are your thoughts on "When empty is not empty"?

Comments powered by Laravel Comments
Want to join the conversation? Log in or create an account to post a comment.