Req #39579 [Com]: Comparing zero & string values in boolean comparison has unexpected behaviour

From: Date: Fri, 19 Jun 2020 16:24:55 +0000
Subject: Req #39579 [Com]: Comparing zero & string values in boolean comparison has unexpected behaviour
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-227559@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=39579&edit=1

 ID:                 39579
 Comment by:         amfriedman at gmail dot com
 Reported by:        iain at workingsoftware dot com dot au
 Summary:            Comparing zero & string values in boolean comparison
                     has unexpected behaviour
 Status:             Not a bug
 Type:               Feature/Change Request
 Package:            Variables related
 Operating System:   FreeBSD 6.1
 PHP Version:        5.2.0
 Block user comment: N
 Private report:     N

 New Comment:

This "feature" just burned an hour of my time as I wracked my brain trying figure out why
a continue; statement in my foreach loop was being triggered. I had an value of (int) 0 in one of
the array items, and it passed an if-test that compared it to a particular string. Super
frustrating.

I think PHP should generate a Notice to give the developer a head's up about this
"gotcha".


Previous Comments:
------------------------------------------------------------------------
[2014-05-28 13:53:44] rasmus@php.net

The transitive property of equality doesn't apply to a type-coercing equality check because the
types matter in each comparison. So you can't say that since
0 == '0' and 0 == 'a' then '0' must be equivalent to 'a'. In
the first two comparisons you are comparing integers to strings and in the last one you are
comparing two strings. These are completely different situations for a type-coercing equality
operator like ==
If you don't want to juggle types, simply use ===

------------------------------------------------------------------------
[2014-05-28 13:25:20] tom at r dot je

To expand on my point above:

0 == '0' //TRUE

Here, 0 and '0' are equivalent. However:

 0 == 'a'; //TRUE
'0' == 'a'; //FALSE

Here, 0 and '0' are not equivalent which is very inconsistent. 

If 0 is equivalent to '0' and 0 is equivalent to 'a' than it logically follows
that '0' is equivalent to 'a'; which is clearly not the case, and nor should it
be to fix this logical contradiction the only option is to make 0 and 'a' not equivalent. 


As for the problems presented above about actually implementing a change, why not do what's
been done before and add an INI setting (settable via ini_set). Any scripts which do rely on this
broken functionality can just call ini_set for compatibility with the old operator.

------------------------------------------------------------------------
[2014-05-27 15:41:55] tom at r dot je

I have to agree with the above, this is illogical and confusing. What just caught me out was an
internal conversion from string to int which triggered the bug (and yes I definitely consider this a
bug.) Try this:

<?php
$arr = array('0' => 'Abc');

$keys = array_keys($arr);

if ($keys[0] == 'foo') {
	echo 'String\'s equal';
}
?>

------------------------------------------------------------------------
[2013-11-07 23:18:58] duerra at yahoo dot com

I'm sorry, but this is just silly.  This has to be one of PHP's most glaring weaknesses. 
While it can be understood, this does NOT make it logical.  In fact, unless you have a very firm
understanding of both how PHP casts strings to integers, and always explicitly know or cast your
types (which PHP's design largely tries to avoid having users worry about), this becomes an
issue that can hit somebody out of nowhere, unexpectedly, and leave them wracking their brains
trying to sort out.

root@host:/bright/Bright# php -r "echo (0 == 'string') ? 'TRUE' :
'FALSE';"
TRUE
root@host:/bright/Bright# php -r "echo (0 == '1string') ? 'TRUE' :
'FALSE';"
FALSE 
root@host:/bright/Bright# php -r "echo ('0' == 'string1') ?
'TRUE' : 'FALSE';"
FALSE
root@host:/bright/Bright# php -r "echo (1 == 'string') ? 'TRUE' :
'FALSE';"
FALSE  
root@host:/bright/Bright# php -r "echo (1 == '1string') ? 'TRUE' :
'FALSE';"
TRUE   
root@host:/bright/Bright# php -r "echo (1 == 'string1') ? 'TRUE' :
'FALSE';"
FALSE  

I realize and understand that this may never change, but that doesn't make it logical or
correct, and in the meantime you're probably allowing more bugs in the wild than you would
cause by actually fixing the issue or using one of the other suggestions from this thread (such as
throwing a Notice).

------------------------------------------------------------------------
[2013-10-22 21:42:58] mirroredfate at gmail dot com

There is another option: when a string casting to an int fails inside a conditional statement, the
conditional evaluates to false.

>Both of these changes would wreak unspeakable havoc on existing applications, and probably
>wouldn't make any tremendous difference overall to the uninitiated.

Really? I am genuinely curious as to why anyone would actually use '(0 == 'string')
to determine if a string could not be cast to an int. This seems kind of like a "rip the
band-aid off" situation to me. Let people know a few patches ahead of time, then go ahead  with
the change. After all, PHP had no problem removing JSON.

The fact that it could cause problems is one of the biggest reasons why one should not design
stupid, counter-intuitive stuff the first place.

------------------------------------------------------------------------


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    https://bugs.php.net/bug.php?id=39579


--
Edit this bug report at https://bugs.php.net/bug.php?id=39579&edit=1


Thread (29 messages)

« previous php.bugs (#227559) next »