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 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 using isset() and a Losse Comparision withfalse.
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, upgrade 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 of empty() 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. Let’s look at all cases when empty() returns true, 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() returns true when the argument is an undefined variable.
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.
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.
💡 Avoid writing code that relies on including files that declare variables or return values.
Undefined instance property
empty() returns true when the argument is an undefined instance property.
value)); // 👋(bool)true
What are scenarios where you currently use empty() and deal with an undefined instance property?
Undefined static property
empty() returns true when the argument is an undefined static property.
console.log( 'Code is Poetry' );
What are scenarios where you currently use empty() and deal with an undefined static property?
Inaccessible instance property
empty() returns true when the argument is an inaccessible instance property.
As a side effect, empty() invokes the magic method __isset() when it exists.
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() returns true when the argument is an inaccessible static property.
What are scenarios where you currently use empty() and deal with an inaccessible static property?
Scenario: Declaring variables in files and including them
Null
empty() returns true when the argument is null.
What are scenarios where you currently use empty() to verify that a value is not null?
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 or static property with null and handle each possible case separately.
value)) {
+ if ($this->value === null) {
// ...
}
+ // handle other possible types and values
+
// ...
}
}
Instead of using empty() to verify the property value when the property can assume null or a known type, add a nullable property declaration and compare the property value with null.
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 with null and handle each possible case separately.
Instead of using empty() to verify the parameter value when the parameter can assume null or a known type, add a nullable parameter type declaration and compare the parameter with 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 with null and handle each possible case separately.
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 assume null or a known type, add a nullable return type declaration and compare the return value with null
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() returns true when the value is an empty array.
What are scenarios where you currently use empty() to verify that a value is not an empty array?
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 or static property with an empty array 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 an array, add an array property declaration and compare the property value with an empty array.
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 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 empty array and handle each possible case separately.
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 empty array, add an array return type declaration and compare the return value with an empty array.
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() returns true when the argument is a bool with the value false.
What are scenarios where you currently use empty() to verify that a value is not a bool with the value false?
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 or static property with false and handle each possible case separately.
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 a bool, add a bool property declaration and use a logical expression.
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 with false and handle each possible case separately.
Instead of using empty() to verify the parameter value when the parameter can assume a bool, add a bool parameter type declaration and use a logical expression.
💡 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 value false.
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 false and handle each possible case separately.
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 a bool, add a bool return type declaration and use a logical expression.
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() returns true when a variable is a float with the value 0.0 or -0.0.
What are scenarios where you currently use empty() to verify that a value is not a float with the value 0.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 or static property with 0.0 or -0.0 and handle each possible case separately.
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 a float, add a float property declaration and compare the instance or static property with 0.0 or -0.0.
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 value 0.0 or -0.0.
Instead of using empty() to verify the parameter value when the parameter can assume multiple types, compare the parameter with 0.0 or -0.0 and handle each possible case separately.
Instead of using empty() to verify the parameter value when the parameter can assume a float, add a float parameter type declaration and compare the parameter with 0.0 or -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 value 0.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 with 0.0 or 0.0 and handle each possible case separately.
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 a float, add a float respan 0.0 or -0.0.
bar()) {
+if ($foo->bar() === 0.0) {
// ...
}
Int
empty() returns true when the argument is an int with the value 0.
What are scenarios where you currently use empty() to verify that a value is not an int with the value 0?
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 or static property with 0 and handle each possible case separately.
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 an int, add an int property declaration and compare the instance or static property with 0.
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 value 0.
Instead of using empty() to verify the parameter value when the parameter can assume multiple types, compare the parameter with 0 and handle each possible case separately.
Instead of using empty() to verify the parameter value when the parameter can assume an int, add an int parameter type declaration and compare the parameter with 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.
You have a function or a method with a return value that could be an int with the value 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 0 and handle each possible case separately.
Scenario: Function or method return value could be 0
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 an int, add an int return type declaration and compare the return value with 0.
bar()) {
+if ($foo->bar() === 0) {
// ...
}
String
empty() returns true when the argument is a string with the value ‘ ‘
empty() also returns true when the argument is a string with the value ‘0’.
What are scenarios where you currently use empty() to verify that a value is not a string 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 or static property with ‘ ‘ (or ‘0’) and handle each possible case separately.
value)) {
+ if ($this->value === '') {
// ...
}
+ // handle other possible types and values
+
// ...
}
}
Instead of using empty() to verify the property value when the property can assume a string, add a string property declaration and compare the instance or static property with ‘ ‘ (or ‘0’).
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.
Instead of using empty() to verify the parameter value when the parameter can assume a string, add a string parameter type declaration and compare the parameter with ” (or ‘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 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.
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 a string, add a string return type declaration and compare the return value with ” (or ‘0’).
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() returns true when the argument is an instance of SimpleXMLElement constructed from an XML string representing an element without attributes and children.
');
var_dump(empty($value)); // (bool)true
What are scenarios where you currently use empty() to verify whether a SimpleXMLElement 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.

No responses yet