Mailcoach is a self-hosted email list manager. It integrates with services like Amazon SES, Mailgun or Sendgrid to send out mailings affordably.

If you're using Laravel, you can learn the techniques we used to create Mailcoach in your own projects by watching the Mailcoach video course.

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.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks 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.