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!