3

I have recently stumbled upon a situation that seems to be a bug at best. Both null and false appear to be evaluated to lower but not equal to negative infinity when used in comparisons.

My current test case:

var_dump(
    PHP_OS,
    PHP_VERSION,
    null == 0,                        # true
    false == 0,                       # true
    INF==INF,                         # true
    (-1*INF) == (-1*INF),             # true
    (-1*INF) < (-1*INF),              # false!
    (-1*INF) > (-1*INF),              # false!
    'Insane In The Membrane',
    null == (-1*INF),                 # false!?
    false == (-1*INF),                # false!?
    null  < (-1*INF),                 # true!
    false < (-1*INF)                  # true!
);

This was run on various PHP Versions and on some windows machines that I had access to. All had the surprising same result.


Ignoring the first two debug dumps, The next 6 results are what you'd expect if you're a seasoned PHP developer. The first two are due to type juggling and the last 4, are due to PHP and math.


Now the last four are what's bugging me.

I'm uncertain if it is even valid in math to have something lower than negative infinity.

What's stranger still is the combination of the first two and the last two comparisons. Somehow the same type juggling algorithm makes this valid:

var_dump(
    'Insane In The Membrane (Redux)',
    (null  == 0) && (null  < (-1*INF)),     # true
    (false == 0) && (false < (-1*INF))      # true
);

If anyone can give any insight as to how these type casts are being evaluated so differently and why that would be greatly appreciated.


P.S. I have tried searching SO again and again and again, the PHP Manual and even the PHP bug tracker, all to no avail. I tried looking through the C source code to determine the bits and pieces that make this code work the way it does. Still no dice.

Community
  • 1
  • 1
Khez
  • 10,172
  • 2
  • 31
  • 51
  • 3
    Who would've thought; PHP's byzantine type-conversion rules are still leading to inexplicable behaviour ;) – Oliver Charlesworth Jan 16 '13 at 12:57
  • I suppose one interpretation is that `null` certainly isn't *greater* than -inf, and it isn't *equal* to -inf. So by elimination... – Oliver Charlesworth Jan 16 '13 at 13:02
  • @OliCharlesworth Heh, I agree with it not being _equal_, but why wouldn't it be _greater_ ? It should be evaluated to 0 (as it is in the second scenario of my question) and **be** greater than `-inf`. I'm puzzled by what exactly is passed to the `cmp` assembly instruction. I don't know how infinity is handled and right now I have no idea how `null` and `false` are handler either. – Khez Jan 16 '13 at 13:09
  • PHP translates the number to a boolean, not the boolean (or null here) to a number. See my answer. – argentage Jan 16 '13 at 20:21

2 Answers2

2

I just was looking at this yesterday. We'll venture to the PHP manual and look at the comparison operators page:

http://php.net/manual/en/language.operators.comparison.php

There is a great chart there that explains what happens when objects of different types are compared, and this is one of its columns:

bool or null    anything    Convert to bool, FALSE < TRUE

So, null is casted to false and any nonzero number is casted to true. Source And, as you can see, FALSE < TRUE. This is why you get supposedly insane behavior - As to why this might be the case, it may be because of C's similar behavior. (But C never lets you play this fast and loose with the typing system!)

argentage
  • 2,758
  • 1
  • 19
  • 28
1

Maybe this will help:

http://gynvael.coldwind.pl/?id=492

It mostly covers the == operator but also has some info and pointers about how comparisons work in general.

Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • At best, that link offers insight as to why `null==0` and `null!=(-1*INF)`, which as mentioned, seasoned developers already understand why. The problem appears to be strictly with the __less than__ operator, making `null` and `false` less than **ANY NUMBER** (except +/- 0). – Khez Jan 16 '13 at 13:44