12

"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?

  • 2
    duplicate of : stackoverflow.com/questions/523643/…. It's the same in both PHP and javascript check the answer below accepted answer. – Walfrat Dec 19 '16 at 9:58
  • 5
    It's because PHP goes to great lengths to be as inconsistent, with both itself and every other programming language, as possible. – David Arno Dec 19 '16 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 Dec 19 '16 at 10:19
  • 1
    @DavidArno exactly ;) – linuxunil Dec 19 '16 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 Dec 19 '16 at 12:48
12

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 - ones 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'

  • 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 Dec 19 '16 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 Dec 19 '16 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 Dec 19 '16 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. – Michael Tsang Dec 20 '16 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 Sep 29 '18 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.

  • 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. – Michael Tsang Dec 20 '16 at 1:17

protected by gnat Jun 9 at 6:19

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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