Hacker News new | past | comments | ask | show | jobs | submit login
Why I avoid using empty() in PHP? A Closer Look (azizdev.medium.com)
16 points by mooreds 9 months ago | hide | past | favorite | 30 comments



This entire post is dedicated to using the wrong tool for the job…

Use isset if you want to see if the variable is set, you should never be casting client input unless it’s coming from query params (or form post I guess but at that point use JSON).

“empty” is a useful tool, provided you take into account things like “is this allowed to be 0/empty-string/etc”.

Lastly:

> After a lengthy debugging session, we realized that empty() was treating 0 as "empty", causing our validation to fail unexpectedly.

Lengthy? To notice an empty check failing? Look, the codebase I work on has its warts, all older codebases do, but unless you have no XDebug, forgot how to log to file or echo to the client, and/or aren’t capable of searching a codebase for the error you got and tracing it back from there then I can’t believe that would be a “Lengthy” process to track down. Even if you are returning a generic error to the client, surely you are logging the real error to a log somewhere?


It's a common mistake that newcomers to the language make. You assume empty is an empty string check when it's really a falsy check that is equivalent to: (!isset($var) || !$var)


it's not always that straight forward to connect xdebug to where you need it, especially if that is triggered by some API call from external uncontrolled system. if that error could just trigger some generic error like product/entry/item is invalid so you would have no idea with exact condition failed. finally there in e-commerce offer there are import processes that get thousands of products in single batch, logging will get very messy and getting to that one product that had issue might take some time in each run

we had some errors that were happening to only one client and noone could reproduce that.


Maybe don't call a screwdriver a hammer.

I don't know enough PHP.

Does isset return true or false if I set a string variable to "" before I call isset?


`isset` will return true/false and it will only return false if the value is null (never initialized or specifically set to null).

Example:

    $myVar = null;
    var_dump(isset($myVar)); // false
    $myVar = '';
    var_dump(isset($myVar)); // true
    $myVar = '0';
    var_dump(isset($myVar)); // true
    $myVar = 0;
    var_dump(isset($myVar)); // true
If you have a property on a class that was never given a value it will also return `false`:

    class MyClass {
        public $myProp;
        
        function myFunction() {
            var_dump(isset($this->myProp)); // false
        }
    }


So isset and empty don't actually check what their name suggests.

I think the problem is finding a short name for a little complex functionality


If you want to find sane function naming, PHP is only going to disappoint you. I say that as someone who likes PHP, the old function names (and argument order) are… not great.

isset is like is_null but one thing isset can do is look at a whole chain (class props or associate array keys) and not blow up.

What I mean by that is you can do

    $test = null;
    isset($test->fake[‘doesNotExist’]->stilFake); // false
Whereas is_null would throw an error trying to walk a fake path. “isset” does essentially a try/catch-type thing around the check it’s doing.


Thankfully others have correctly identified this is not a real use case for empty and someone wrote an entire article about it.

The value that empty() provides in PHP is similar to a null coalescing operator in many languages:

    if (empty($foo->bar['baz'])) {
In this line of code all of the above can be missing. $foo can be an undefined variable, let alone one that has a value, and likewise all of the members, arrays, keys, etc. can also be missing. It does not throw an exception or trigger any warnings/errors to be logged, since, well, that's the purpose of empty.

If you want similar-ish behavior but you're not interested in the problems associated with the empty semantics, use isset() as it has the same properties for non-existent keys.


It's not a matter of avoiding empty(). It's a matter of only using it when it's the correct tool. The examples were examples of someone using a screwdriver when they needed a hammer. That's not the screwdriver's fault.


If the screwdriver is called hammer I would blame the manufacturer.

An int with the value 0 isn't empty.


What value would an empty int have, then?


If it's not nullable and not undefined it's not empty.

If an int with 0 is empty a string with a only white spaces is the same kind of empty.

I think empty mixes the computer meaning of empty with the linguistic meaning.


What is the computer meaning of "empty?"

I'll answer - there really isn't one. You could say "undefined" but we already have another word for that ("undefined") - an "empty" construct doesn't exist in any other programming language that I'm aware of. Back in PHP's way-too-helpful days, they came up with this concept, so they got to define what it meant. (And to be fair, as with other things from the bad old days, it has caused confusion ever since.)


You are using comparison like this after a float cast?? That's a paddlin'.


Yep, that whole example after the float cast is bit silly. After the cast, the value can never be an empty string, or null. Not to mention, comparing a floating point value to an arbitrary, literal value (of zero in this case) is potentially problematic [1].

[1]: See the warning on this page, this applies to all languages with floating point arithmetic. https://www.php.net/manual/en/language.types.float.php


In PHP, as in other languages, numeric types that aren't ints should be avoided as much as possible. If you don't know why, smarter people can explain it, but the basics are that the binary nature of computers (every value is 0, 1, or a combination thereof) doesn't really work for reflecting decimal values without some level of fakery.

When working with things like money amounts, lengths, etc, store values as ints of the smallest denominator you support. For example, store $1.23 as 123 cents, or 4.567 meters as 4567 tenths of a centimeter. If you want to still allow the user to be able to, for example, enter a price as 1.23, multiply by 100 on input (like `$priceInCents = round($_POST['price'] * 100);`) and divide by 100 when displaying the value(`number_format($priceInCents / 100, 2)`), but keep it as an int all the way in between.

In terms of PHP, this also makes empty() a lot more predictable, because once a value is cast as int, the only time empty() will return true is if it is zero - or you could explicitly code `$priceInCents === 0` and have the exact same result.


All programming languages have some problems in this department. Some lisps for instance use the empty list nil for false, others have a distinct #f value. Each of those choices has strengths and weaknesses.

Dynamic programming languages usually have some arbitrary rules about what X is treated true or false in

  if(X) (…}
whatever rules are used are what you want almost always except for the times that they aren’t. A strongly typed language like Java will require X to be a boolean which now puts a load on the programmer to choose some f such that

   if(f(X)) {}
which could be correct every time in principle but a small increase in cognitive load is certain while most likely the f you choose (inclusive of your choice and it’s action) will do the right thing almost all the time except when it doesn’t. So I wouldn’t laugh at any particular programming language’s almost-right choice for ‘casting’ any to boolean because people are going to screw it up in any programming language.


There's an entire subreddit making fun of PHP quirks:

https://www.reddit.com/r/lolphp

Here the top posts of all time:

https://www.reddit.com/r/lolphp/top/?t=all


In both examples, to check distance and price, the author should have simply used is_numeric()


Do you guys know if `!isset()` is a good alternative ? Or if it also has some shortcomings ?


isset() is a great additional tool and has most of the same properties of empty(), except it deals explicitly with null. Most importantly it doesn't produce exceptions, errors, warnings or notices when keys are missing or you attempt to de-reference null.


Alternative to what exactly? Both empty(), isset() and implicit casting to boolean are useful tools for their specific purposes.


isset($var) will return false if you have deliberately set $var === NULL

Otherwise more or less fine?

The whole OP here is a longwinded way of observing that several built-in PHP functions don't know anything about types. You can't use switch() as it's usually documented either, for example, because that ignores types too.

There are ways around all these things, of course. PHP that doesn't suck is kind of the norm these days. Just stay the hell away from Wordpress


How can WordPress be so prominent and have so much money behind it and still have such garbage code? Are there giant companies still running PHP 4 server farms that need it to continue to be coded to 2003 standards? Is it some government op to ensure a good deal of the sites on the web are easily-hackable? Someone explain this to me.


This should be a lesson for everyone. Code quality doesn't matter, language doesn't matter, it only matters if people want your product. If you would look at the code quality of the most successful WordPress plugins you would be... uh, amazed? Compared to them WordPress' code quality is top notch. Yet, they probably bring in million/month from subscriptions. If you're curious see WpAllImport


I'm sorry, what code exactly did you find to be garbage?


Thankfully it's been a couple years since I had to touch a WordPress code base, but I remember being confused because I needed to define a route and couldn't figure out how to do so either in the code base or in documentation scattered about online. Eventually I realized that this was because WORDPRESS DOESN'T HAVE A ROUTER and you're supposed to just create .php files which are called and executed directly from the web server. True caveman smash-together-rocks shit.


This is not true. WordPress routes request in its own, admittedly shitty way, but it has a router. I don't remember where it is, but it exists. It parses rewrite rules and matches them against the request URI.


Scroll below the article for another article about isset.


While I appreciate the availability of empty(), I appreciate this article as it clearly states why we should use stricter comparisons. Avoid mistakes, and conserve resources.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: