Avoiding empty() in PHP
The language construct empty()
appears rather versatile. It's like a Swiss army knife with a thousand blades, ready to hurt you if you grab it by the wrong end. Or a jack of all trades, master of none. Most of all, empty()
is a poor communicator.
I spot empty()
in poorly-aged closed-source projects. I discover empty()
in brand-new closed-source projects from last week. And I meet empty()
again in open-source projects with millions of downloads.
So what is the problem with empty()
when so many people use it?
Problem
If you refer to the documentation for empty()
, you will find the following:
Determine whether a variable is considered to be empty. A variable is considered empty if it does not exist or if its value equals
false
.empty()
does not generate a warning if the variable does not exist.PHP manual: empty()If you ignore the internal implementation and possible performance issues, using
empty()
is identical to usingisset()
and a loose comparison withfalse
.
<?php declare(strict_types=1); -if (empty($value)) { +if (!isset($value) || $value == false) { // ... }
When you already know that a variable, a property, a function or method parameter, and a function or method return value are defined, why would you use
isset()
?When you already know that a variable, a property, a function or method parameter, and a function or method return value assume multiple types, why would you use loose comparison and not handle each acceptable type and value separately?
When you already know that a variable, a property, a function or method parameter, and a function or method return value assume a single type, why would you use loose instead of strict comparison?
Using
empty()
,isset()
, or loose comparisons is a wishy-washy business. Is that how you want to work?As mentioned, I often find
empty()
in legacy code bases. Some of these projects run on outdated versions of PHP and are entirely unaware of property, parameter, and return type declarations. In these projects, you often can not find DocBlocks for properties, function and method parameters, or function and method return types.When you pick up maintenance of these projects and begin to fix bugs, update PHP versions and eventually modernize them, you have difficulty figuring out what the original authors intended to do when they used
empty()
.Were the original authors aware of the quirks of
empty()
? Did the authors intend a property, a function, or a method parameter to accept all types and values? Did the authors plan to return all types and values from a function or method? Did the authors, who have long disappeared and ghosted the project owners, really think the use ofempty()
through?The original author could be you. The maintainer could also be you, picking up the project after years. Perhaps you had a stroke or an accident in the meantime that impaired your cognitive abilities. Now you have difficulty understanding what the original author intended. Perhaps the authors and maintainers are entirely different persons. Maybe you are in perfect health and still struggle to understand the original author's intent.
While you write the code for the computer to process, you - as the author - also write the code for the person maintaining it after. By more or less carefully selecting language features, you instruct the computer, but you also communicate your intent to the maintainer.
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Martin Fowler, RefactoringLet's look at all cases when
empty()
returnstrue
, and explore alternatives that better communicate your situational awareness and intent!Candidates
- undefined variable
- undefined instance property
- undefined static property
- inaccessible instance property
- inaccessible static property
- null
- array
- bool
- float
- int
- string
- SimpleXMLElement
Undefined variable
empty()
returnstrue
when the argument is an undefined variable.
<?php declare(strict_types=1); var_dump(empty($value)); // (bool)true
What are scenarios where you currently use
empty()
to verify whether a variable is undefined?Scenario: Expecting an included file to declare a variable
You include a file that you expect to declare a variable. The file may not exist or may not declare the variable.
Instead of using
empty()
to verify that an included file exists and declares a variable, set the variable to a suitable default value, include the file when it exists, and verify that the variable has an acceptable type and value.
<?php declare(strict_types=1); -include __DIR__ . '/file.php'; +$file = __DIR__ . '/file.php'; -if (empty($value)) { - // .... -} + +$value = []; + +if (is_file($file)) { + include $file; + + if (!is_array($value)) { + // ... + } +}
Instead of using
empty()
to verify that an included file exists and declares a variable, set the variable to a suitable default value, expect the file to return a value, include the file when it exists, and verify that the returned value has an acceptable type and value.
<?php declare(strict_types=1); -include __DIR__ . '/file.php'; +$file = __DIR__ . '/file.php'; -if (empty($value)) { - // .... -} + +$value = []; + +if (is_file($file)) { + $value = include $file; + + if (!is_array($value)) { + // ... + } +}
💡 Avoid writing code that relies on including files that declare variables or return values.
Undefined instance property
empty()
returnstrue
when the argument is an undefined instance property.
<?php declare(strict_types=1); $object = new stdClass(); var_dump(empty($object->value)); // (bool)true
As a side effect,
empty()
also invokes the magic method__isset()
when you reference an undefined instance property of an object that declares an__isset()
method.
<?php declare(strict_types=1); $object = new class() { public function __isset(string $name): bool { echo '👋'; return true; } }; var_dump(empty($object->value)); // 👋(bool)true
What are scenarios where you currently use
empty()
and deal with an undefined instance property?Undefined static property
empty()
returnstrue
when the argument is an undefinedstatic
property.
<?php declare(strict_types=1); $object = new stdClass(); var_dump(empty($object::$value)); // (bool)true
What are scenarios where you currently use
empty()
and deal with an undefinedstatic
property?Inaccessible instance property
empty()
returnstrue
when the argument is an inaccessible instance property.As a side effect,
empty()
invokes the magic method__isset()
when it exists.
<?php declare(strict_types=1); $object = new class() { private $value = 9000; protected $otherValue = 9001; public function __isset(string $name): bool { echo '👋'; return true; } }; var_dump(empty($object->value)); // 👋(bool)true var_dump(empty($object->otherValue)); // 👋(bool)true
What are scenarios where you currently use
empty()
and deal with an inaccessible instance property?Inaccessible static property
empty()
returnstrue
when the argument is an inaccessiblestatic
property.
<?php declare(strict_types=1); $object = new class() { private static $value = 9000; protected static $otherValue = 9000; }; var_dump(empty($object::$value)); // (bool)true var_dump(empty($object::$otherValue)); // (bool)true
What are scenarios where you currently use
empty()
and deal with an inaccessiblestatic
property?Scenario: Declaring variables in files and including them
Null
empty()
returnstrue
when the argument isnull
.
<?php declare(strict_types=1); $value = null; var_dump(empty($value)); // (bool)true
What are scenarios where you currently use
empty()
to verify that a value is notnull
?Scenario: Instance or static property could be null
You have a class with an instance or a static property and currently use
empty()
to verify the property value.Instead of using
empty()
to verify the property value when the property can assume multiple types, compare the instance orstatic
property withnull
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { private $value; public function bar() { - if (empty($this->value)) { + if ($this->value === null) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the property value when the property can assumenull
or a known type, add a nullable property declaration and compare the property value withnull
.
<?php declare(strict_types=1); final class Foo { - private $value; + private ?string $value = null; public function bar() { - if (empty($this->value)) { + if ($this->value === null) { // ... } // ... } }
💡 Avoid writing classes with instance or static properties that accept multiple types. Add property type declarations or DocBlocks to document property types.
Scenario: Function or method parameter could be null
You have a function or a method with a parameter that could be
null
.Instead of using
empty()
to verify the parameter value when the parameter can assume multiple types, compare the parameter withnull
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar($value) { - if (empty($value)) { + if ($value === null) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the parameter value when the parameter can assumenull
or a known type, add a nullable parameter type declaration and compare the parameter withnull
.
<?php declare(strict_types=1); final class Foo { - public function bar($value) + public function bar(?string $value) { - if (empty($value)) { + if ($value === null) { // ... } // ... } }
💡 Avoid writing functions or methods with parameters that accept multiple types. Add parameter type declarations or DocBlocks to document function and method parameter types.
Scenario: Function or method return value could be null
You have a function or a method with a return value that could be
null
.Instead of using
empty()
to verify the return value at the call site when the return value can assume multiple types, compare the return value withnull
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar() { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === null) { // ... } +// handle other possible types and values
Instead of using
empty()
to verify the return value at the call site when the return value can assumenull
or a known type, add a nullable return type declaration and compare the return value withnull
.
<?php declare(strict_types=1); final class Foo { - public function bar() + public function bar(): ?string { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === null) { // ... }
💡 Avoid writing functions or methods that return values of multiple types. Add return type declarations or DocBlocks to document function and method return types.
Array
empty()
returnstrue
when the value is an emptyarray
.
<?php declare(strict_types=1); $value = []; var_dump(empty($value)); // (bool)true
What are scenarios where you currently use
empty()
to verify that a value is not an emptyarray
?Scenario: Instance or static property could be an empty array
You have a class with an instance or a static property and currently use
empty()
to verify the property value.Instead of using
empty()
to verify the property value when the property can assume multiple types, compare the instance orstatic
property with an emptyarray
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { private $value; public function bar() { - if (empty($this->value)) { + if ($this->value === []) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the property value when the property can assume anarray
, add anarray
property declaration and compare the property value with an emptyarray
.
<?php declare(strict_types=1); final class Foo { - private $value; + private array $value = []; public function bar() { - if (empty($this->value)) { + if ($this->value === []) { // ... } // ... } }
💡 Avoid writing classes with instance or static properties that accept multiple types. Add property type declarations or DocBlocks to document property types.
Scenario: Function or method parameter could be an empty array
You have a function or a method with a parameter that could be an empty
array
.Instead of using
empty()
to verify the parameter value when the parameter can assume multiple types, compare the parameter with an emptyarray
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar($value) { - if (empty($value)) { + if ($value === []) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the parameter value when the parameter can assume anarray
, add anarray
parameter type declaration and compare the parameter with an emptyarray
.
<?php declare(strict_types=1); final class Foo { - public function bar($value) + public function bar(array $value) { - if (empty($value)) { + if ($value === []) { // ... } // ... } }
💡 Avoid writing functions or methods with parameters that accept multiple types. Add parameter type declarations or DocBlocks to document function and method parameter types.
Scenario: Function or method return value could be an empty array
You have a function or a method with a return value that could be an empty
array
.Instead of using
empty()
to verify the return value at the call site when the return value can assume multiple types, compare the return value with an emptyarray
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar() { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === []) { // ... } +// handle other possible types and values
Instead of using
empty()
to verify the return value at the call site when the return value can assume an emptyarray
, add anarray
return type declaration and compare the return value with an emptyarray
.
<?php declare(strict_types=1); final class Foo { - public function bar() + public function bar(): array { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === []) { // ... }
💡 Avoid writing functions or methods that return values of multiple types. Add return type declarations or DocBlocks to document function and method return types.
Boolean
empty()
returnstrue
when the argument is abool
with the valuefalse
.
<?php declare(strict_types=1); $value = false; var_dump(empty($value)); // (bool)true
What are scenarios where you currently use
empty()
to verify that a value is not abool
with the valuefalse
?Scenario: Instance or static property could be false
You have a class with an instance or a static property and currently use
empty()
to verify the property value.Instead of using
empty()
to verify the property value when the property can assume multiple types, compare the instance orstatic
property withfalse
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { private $value; public function bar() { - if (empty($this->value)) { + if ($this->value === false) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the property value when the property can assume abool
, add abool
property declaration and use a logical expression.
<?php declare(strict_types=1); final class Foo { - private $value; + private bool $value = false; public function bar() { - if (empty($this->value)) { + if (!$this->value) { // ... } // ... } }
💡 Avoid writing classes with instance or static properties that accept multiple types. Add property type declarations or DocBlocks to document property types.
Scenario: Function or method parameter could be false
You have a function or a method with a parameter that could be an empty
array
.Instead of using
empty()
to verify the parameter value when the parameter can assume multiple types, compare the parameter withfalse
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar($value) { - if (empty($value)) { + if ($value === false) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the parameter value when the parameter can assume abool
, add abool
parameter type declaration and use a logical expression.
<?php declare(strict_types=1); final class Foo { - public function bar($value) + public function bar(bool $value) { - if (empty($value)) { + if (!$value) { // ... } // ... } }
💡 Avoid writing functions or methods with parameters that accept multiple types. Add parameter type declarations or DocBlocks to document function and method parameter types.
Scenario: Function or method return value could be false
You have a function or a method with a return value that could be a
bool
with the valuefalse
.Instead of using
empty()
to verify the return value at the call site when the return value can assume multiple types, compare the return value withfalse
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar() { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === false) { // ... } +// handle other possible types and values
Instead of using
empty()
to verify the return value at the call site when the return value can assume abool
, add abool
return type declaration and use a logical expression.
<?php declare(strict_types=1); final class Foo { - public function bar() + public function bar(): bool { // ... return $value; } } -if (empty($foo->bar()) { +if (!$foo->bar()) { // ... }
💡 Avoid writing functions or methods that return values of multiple types. Add return type declarations or DocBlocks to document function and method return types.
Float
empty()
returnstrue
when a variable is afloat
with the value0.0
or-0.0
.
<?php declare(strict_types=1); $value = 0.0; var_dump(empty($value)); // (bool)true
What are scenarios where you currently use
empty()
to verify that a value is not afloat
with the value0.0
or-0.0
?Scenario: Instance or static property could be 0.0
You have a class with an instance or a static property and currently use
empty()
to verify the property value.Instead of using
empty()
to verify the property value when the property can assume multiple types, compare the instance orstatic
property with0.0
or-0.0
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { private $value; public function bar() { - if (empty($this->value)) { + if ($this->value === 0.0) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the property value when the property can assume afloat
, add afloat
property declaration and compare the instance orstatic
property with0.0
or-0.0
.
<?php declare(strict_types=1); final class Foo { - private $value; + private float $value = 0; public function bar() { - if (empty($this->value)) { + if ($this->value === 0.0) { // ... } // ... } }
💡 Avoid writing classes with instance or static properties that accept multiple types. Add property type declarations or DocBlocks to document property types.
Scenario: Function or method parameter could be 0.0
You have a function or a method with a parameter that could be a
float
with the value0.0
or-0.0
.Instead of using
empty()
to verify the parameter value when the parameter can assume multiple types, compare the parameter with0.0
or-0.0
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar($value) { - if (empty($value)) { + if ($value === 0.0) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the parameter value when the parameter can assume afloat
, add afloat
parameter type declaration and compare the parameter with0.0
or-0.0
.
<?php declare(strict_types=1); final class Foo { - public function bar($value) + public function bar(float $value) { - if (empty($value)) { + if ($value === 0.0) { // ... } // ... } }
💡 Avoid writing functions or methods with parameters that accept multiple types. Add parameter type declarations or DocBlocks to document function and method parameter types.
Scenario: Function or method return value could be 0.0
You have a function or a method with a return value that could be a
float
with the value0.0
or-0.0
.Instead of using
empty()
to verify the return value at the call site when the return value can assume multiple types, compare the return value with0.0
or0.0
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar() { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === 0.0) { // ... } +// handle other possible types and values
Instead of using
empty()
to verify the return value at the call site when the return value can assume afloat
, add afloat
return type declaration and compare the return value with0.0
or-0.0
.
<?php declare(strict_types=1); final class Foo { - public function bar() + public function bar(): float { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === 0.0) { // ... }
Int
empty()
returnstrue
when the argument is anint
with the value0
.
<?php declare(strict_types=1); $value = 0; var_dump(empty($value)); // // (bool)true
What are scenarios where you currently use
empty()
to verify that a value is not anint
with the value0
?Scenario: Instance or static property could be 0
You have a class with an instance or a static property and currently use
empty()
to verify the property value.Instead of using
empty()
to verify the property value when the property can assume multiple types, compare the instance orstatic
property with0
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { private $value; public function bar() { - if (empty($this->value)) { + if ($this->value === 0) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the property value when the property can assume anint
, add anint
property declaration and compare the instance orstatic
property with0
.
<?php declare(strict_types=1); final class Foo { - private $value; + private int $value = 0; public function bar() { - if (empty($this->value)) { + if ($this->value === 0) { // ... } // ... } }
💡 Avoid writing classes with instance or static properties that accept multiple types. Add property type declarations or DocBlocks to document property types.
Scenario: Function or method parameter could be 0
You have a function or a method with a parameter that could be an
int
with the value0
.Instead of using
empty()
to verify the parameter value when the parameter can assume multiple types, compare the parameter with0
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar($value) { - if (empty($value)) { + if ($value === 0) { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the parameter value when the parameter can assume anint
, add anint
parameter type declaration and compare the parameter with0
.
<?php declare(strict_types=1); final class Foo { - public function bar($value) + public function bar(int $value) { - if (empty($value)) { + if ($value === 0) { // ... } // ... } }
💡 Avoid writing functions or methods with parameters that accept multiple types. Add parameter type declarations or DocBlocks to document function and method parameter types.
Scenario: Function or method return value could be 0
You have a function or a method with a return value that could be an
int
with the value0
.Instead of using
empty()
to verify the return value at the call site when the return value can assume multiple types, compare the return value with0
and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar() { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === 0) { // ... } +// handle other possible types and values
Instead of using
empty()
to verify the return value at the call site when the return value can assume anint
, add anint
return type declaration and compare the return value with0
.
<?php declare(strict_types=1); final class Foo { - public function bar() + public function bar(): int { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === 0) { // ... }
String
empty()
returnstrue
when the argument is astring
with the value''
.
<?php declare(strict_types=1); $value = ''; var_dump(empty($value)); // // (bool)true
empty()
also returnstrue
when the argument is astring
with the value'0'
.
<?php declare(strict_types=1); $value = '0'; var_dump(empty($value)); // // (bool)true
What are scenarios where you currently use
empty()
to verify that a value is not astring
with the value''
(or'0'
)?Scenario: Instance or static property could be an empty string
You have a class with an instance or a static property and currently use
empty()
to verify the property value.Instead of using
empty()
to verify the property value when the property can assume multiple types, compare the instance orstatic
property with''
(or'0'
) and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { private $value; public function bar() { - if (empty($this->value)) { + if ($this->value === '') { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the property value when the property can assume astring
, add astring
property declaration and compare the instance orstatic
property with''
(or'0'
).
<?php declare(strict_types=1); final class Foo { - private $value; + private string $value = ''; public function bar() { - if (empty($this->value)) { + if ($this->value === '') { // ... } // ... } }
💡 Avoid writing classes with instance or static properties that accept multiple types. Add property type declarations or DocBlocks to document property types.
Scenario: Function or method parameter could be an empty string
You have a function or a method with a parameter that could be a
string
with the value''
(or'0'
).Instead of using
empty()
to verify the parameter value when the parameter can assume multiple types, compare the parameter with''
(or'0'
) and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar($value) { - if (empty($value)) { + if ($value === '') { // ... } + // handle other possible types and values + // ... } }
Instead of using
empty()
to verify the parameter value when the parameter can assume astring
, add astring
parameter type declaration and compare the parameter with''
(or'0'
).
<?php declare(strict_types=1); final class Foo { - public function bar($value) + public function bar(string $value) { - if (empty($value)) { + if ($value === '') { // ... } // ... } }
💡 Avoid writing functions or methods with parameters that accept multiple types. Add parameter type declarations or DocBlocks to document function and method parameter types.
Scenario: Function or method return value could be an empty string
You have a function or a method with a return value that could be a
string
with the value''
(or'0'
).Instead of using
empty()
to verify the return value at the call site when the return value can assume multiple types, compare the return value with''
(or'0'
) and handle each possible case separately.
<?php declare(strict_types=1); final class Foo { public function bar() { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === '') { // ... } +// handle other possible types and values
Instead of using
empty()
to verify the return value at the call site when the return value can assume astring
, add astring
return type declaration and compare the return value with''
(or'0'
).
<?php declare(strict_types=1); final class Foo { - public function bar() + public function bar(): string { // ... return $value; } } -if (empty($foo->bar()) { +if ($foo->bar() === '') { // ... }
💡 Avoid writing functions or methods that return values of multiple types. Add return type declarations or DocBlocks to document function and method return types.
SimpleXMLElement
empty()
returnstrue
when the argument is an instance ofSimpleXMLElement
constructed from an XML string representing an element without attributes and children.
<?php declare(strict_types=1); $value = new SimpleXMLElement('<foo></foo>'); var_dump(empty($value)); // (bool)true
What are scenarios where you currently use
empty()
to verify whether aSimpleXMLElement
is empty?Conclusion
Do not use
empty()
. Do not write code that allows a variable, a property, a parameter, or a return value to assume multiple types. Use type-safe comparisons.Do you find this article helpful?
Do you have feedback?
Just published: Avoiding empty() in PHP.
— Andreas Möller (@localheinz) May 10, 2023
↓https://t.co/tjOcGWBrxyDo you need help with your PHP project?