14

"0", as a string containing one character, is not something empty intuitively. Why does PHP treat it as FALSE when converted to a boolean, unlike other programming languages?

8
  • 2
    duplicate of : stackoverflow.com/questions/523643/…. It's the same in both PHP and javascript check the answer below accepted answer.
    – Walfrat
    Commented Dec 19, 2016 at 9:58
  • 6
    It's because PHP goes to great lengths to be as inconsistent, with both itself and every other programming language, as possible.
    – David Arno
    Commented Dec 19, 2016 at 10:08
  • 2
    @DavidArno On the contrary, it's doing its best to be consistent; once you start autocasting strings (very handy in a language often grabbing vars from URLs or request bodies) you have to follow through that logic. If '0' is treated as 0 in $x + 1, why shouldn't it also be treated as 0, and therefore false, in if ( $x )?
    – IMSoP
    Commented Dec 19, 2016 at 10:19
  • 1
    @DavidArno exactly ;)
    – linuxunil
    Commented Dec 19, 2016 at 11:19
  • 1
    @DavidArno Once you start performing lossy casts, some inconsistency is inevitable I think; the consistent solution involves rejecting some casts, and designing the rest very carefully. Very few popular languages are designed from scratch though; most evolve either from accidentally-popular experiments, or from older languages with different aims and baggage. Even C#, which has a lot of sound theoretical design, has some legacy from C, which was never intended to be as universal as it became. Snark like "going to great lengths to be inconsistent" is like shouting at the ref at a sports match.
    – IMSoP
    Commented Dec 19, 2016 at 12:48

2 Answers 2

16

PHP was designed (or, rather, evolved) for use with web requests, where you're frequently dealing with string input (URL parameters, or POST requests from a form in a browser). As such, it will automatically cast strings to other types.

A simple example of this is that '1' + '2' gives 3, not an error, or '12', or some other interpretation. By the same logic, the string '0' can be used as a numeric 0.

Meanwhile, like many languages, PHP treats certain values as "falsy" when cast to boolean - things that are intuitively "empty", as you say. That includes numeric 0, as well as the empty string '' and the empty array []. In an if statement, the expression is explicitly cast to boolean, so if ( 0 ) is the same as if ( false ).

Putting these two things together, you get a conundrum: on the one hand, as you say '0' is a non-empty string; on the other hand, we have said that it can be used as a numeric 0, which is "empty". PHP opts to treat the "zero-ness" as more important than the "stringiness", so that '0' is considered "falsy".

In short: '0' == 0 == false; or (bool)'0' === (bool)(int)'0'

7
  • Did somebody downvote my answer just because I dared to defend PHP and answer the question with something other than a cheap and ignorant joke? Or is there something inaccurate or unhelpful in my answer that they would like to point out?
    – IMSoP
    Commented Dec 19, 2016 at 12:03
  • 1
    I think PHP took this from Perl, which has the same “"0" is false” behaviour. In Perl, there literally isn't any user-visible difference between the string "0" and number 0 – annoying when handling JSON, but very intuitive when handling textual data. It is then impossible to have the number 0 be falsey without also the string "0" being falsey. PHP and JavaScript borrow this design decision, but add some confusion by distinguishing strings/bools/numeric types while still allowing implicit conversions (PHP: 0 == "0 foo", 0 == false, but "0 foo" == true: == isn't transitive)
    – amon
    Commented Dec 19, 2016 at 12:49
  • @amon Yes, Perl takes the interesting approach of (nearly) all operators and built-in functions forcing operands to a particular type, with extra operators like eq for string equality. However, this doesn't save it from the non-transitivity of lossy casts:"0 foo" is truthy in a boolean context, but is equal to 0 under ==. So if ( ! $foo ) .. and $false = (1 == 2); if ( $foo == $false ) ... don't give the same result. I guess the language is missing a "boolean equality" operator which could treat this consistently...
    – IMSoP
    Commented Dec 19, 2016 at 13:20
  • Although "0" is 0 when evaluated as numeric, when we use a string in a boolean context (for example in an if statement), we are not interested in its numeric value. If we want to interpret it as numeric, we would compare it with some number, for example, $_POST['id'] == 0, which makes the intent clear that we want to treat the user input as a number. Commented Dec 20, 2016 at 1:20
  • 1
    @MestreLion That example was of Perl rather than PHP. The crucial difference being that there is no separate boolean type in Perl, so $false ends up set to 0; so when you write $foo == $false, Perl doesn't know you want a boolean comparison, and casts to int instead. In PHP, that doesn't happen, because $false is boolean false, so == casts to boolean, giving the same result as !
    – IMSoP
    Commented Sep 29, 2018 at 14:09
3

According to the PHP documentation on booleans, it says that:

When converting to boolean, the following values are considered FALSE
...
the empty string, and the string "0"
...

Otherwise:

Every other value is considered TRUE (including any resource).

If you run:

var_dump((bool) "0");

It will print:

bool(false)

So it's working as expected.


To explicitly answer your question:

However, in most cases the cast is unnecessary, since a value will be automatically converted if an operator, function or control structure requires a boolean argument.

This means that PHP's "autocast" will cast "0" to integer 0, which is FALSE as well in a control structure like say an if() statement.

1
  • I would like to know the rationale of the design decision treating "0" as FALSE when converted to boolean, rather than the need of explicit casting. Commented Dec 20, 2016 at 1:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.