The function shows up everywhere: in Stack Overflow snippets, in AI-generated code, in that “quick fix” someone pushed at 5pm Friday. It’s convenient, it’s short, and it silently breaks your code in ways that are hard to debug. If your boss, your tech lead, or that senior developer keeps telling you not to use it, they’re right. Here’s why, written down so you never have to be reminded again.
What empty()
Actually Does
Most developers know empty()
checks for falsy values. What they might not realize is what it considers falsy:
empty(null); // true
empty(false); // true
empty(0); // true
empty("0"); // true
empty(""); // true
empty([]); // true
empty($undefined); // true
That last line is the biggest problem. When empty()
encounters an undefined variable, it returns true
instead of throwing a warning. This is almost always unexpected behavior.
The Real Danger
Consider this WordPress code where a developer switches two letters:
$payment_gateway = get_option('payment_gateway');
if (empty($paymentGateway)) { // Wrong variable name
$payment_gateway = 'test_mode';
}
The code runs without error. The typo ships to production. Production charges start going to test mode. Any other check would have thrown an “undefined variable” warning and caught the bug immediately.
Beyond typos, empty()
masks function failures by treating them like empty values. WordPress’s get_post_meta()
returns false
when a post doesn’t exist, but returns an empty string when the field is genuinely empty. With empty()
, these two very different states look identical:
// Bad: Can't distinguish "not found" from "empty value"
$price = get_post_meta($post_id, 'price', true);
if (empty($price)) {
return 'Price not set'; // But what if $post_id was invalid?
}
// Good: Check for false (error) separately from empty string
$price = get_post_meta($post_id, 'price', true);
if ($price === false) {
return 'Product not found'; // Invalid post ID
}
if ($price === '' || $price === '0') {
return 'Price not set'; // Legitimate empty value
}
What To Do Instead
Use explicit checks.
Writing if ($price === null || $price === '')
is barely longer than if (empty($price))
, but it generates warnings when you make typos instead of silently hiding them.
The truthiness check !$var
is better than empty()
because it generates warnings for undefined variables, but whether it works correctly depends on your API’s design. Laravel’s Model::find()
returns null
for missing records and throws exceptions for actual errors, so if (!$user)
works as expected. WordPress functions often return different falsy values for different purposes. For example, get_post_meta()
returns false
for an invalid post but an empty string for a missing field. In that case, !$price
can’t distinguish between “the post doesn’t exist” and “the price is empty,” so you need explicit checks: if ($price === false)
for errors versus if ($price === '')
for empty values.
The one exception is checking array keys that might not exist, like form submissions or configuration arrays. Though even here, null coalescing is usually clearer:
// Works, but obscures what you're checking
if (!empty($_POST['subscribe'])) {
subscribe_user_to_newsletter();
}
// Clearer: explicitly provides a default for missing key
if (($_POST['subscribe'] ?? false)) {
subscribe_user_to_newsletter();
}
// WordPress: Feature flags in configuration
$features = get_option('plugin_features', []);
if (($features['beta_mode'] ?? false)) {
enable_beta_features();
}
The ??
operator makes it obvious you’re providing a default for a potentially missing key.
The Bottom Line
empty()
treats undefined variables as normal values, returning true
when it should throw a warning. This silently swallows the errors that matter most: typos, refactoring mistakes, and function failures. These are the bugs you’ll debug at 2am wondering why there’s no error message, no stack trace, no indication anything went wrong. Use explicit checks instead and let your code fail loudly when something breaks.
Leave a Reply