Req #43304 [Com]: Casting During Comparison
| From: | michael dot kluge at wundermedia dot de | Date: | Mon, 16 Jan 2012 14:29:08 +0000 |
| Subject: | Req #43304 [Com]: Casting During Comparison | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-166488@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=43304&edit=1
ID: 43304
Comment by: michael dot kluge at wundermedia dot de
Reported by: ken at smallboxsoftware dot net
Summary: Casting During Comparison
Status: Open
Type: Feature/Change Request
Package: Feature/Change Request
Operating System: ALL
PHP Version: 5.2.5
Block user comment: N
Private report: N
New Comment:
No comments from any PHP devs yet?
Well I strongly disagree with the current implementation.
From PHP-Docs:
$a === $b Identical TRUE if $a is equal to $b, and they are of the same type.
This is the correct definition of the === operator.
An so it should work like that definition:
So
$a = "001234";
$b = "1234";
$a == $b should be equal to $a === $b (both should be false)
as both variables hold the same type
and from the above definition
those expressions should be equal:
$a === $b
($a == $b && typeof($a)==typeof($b))
So if (typeof($a)==typeof($b)) is true, $a===$b should be identical to $a==$b.
If comparing two variables of the same type in NO case any type-conversion should be applied!
If you need conversions in those cases these should be explicitly noted as e.g.:
intval($a) == intval($b)
Adding special exceptions to the general definition doesn't make much sense in my eyes; it just
makes the base definition wrong in certain circumstances and leads to unexpected behaviour in
certain cases (see comment from kissifrot).
We stumbled upon this when comparing certain product ids in use by one of our customers, just being
different in the leading zeros. (So id "001" is another product than "01" ==>
therefore using strings; please don't ask why, as I don't know what reasons might have
caused these strange ids)
delphists said that "there are also lots of cases when numerical strings have to be compared as
integers". I agree with that, but in those cases the developer should convert the types
manually.
Also the example with the database should, in my opinion, be implemented differently:
The model should return integers for integer-typed database fields and not strings.
On the other hand if you expect input parameters containing integer values these could also be
converted to integers, which can be easily done in the validity checks of the parameters.
IMHO, despite of PHP trying to make type-conversions transparent to the developer, the developer
should in any case keep in mind, that PHP is not typeless and respect the types accordingly. And
"0123" and "123" are definitely NOT logically equal in any case! I think the
weird concept of "numerical strings" should be dropped.
Previous Comments:
------------------------------------------------------------------------
[2011-03-11 09:43:13] delphists at apollo dot lv
Sorry for digging up this bug report, but it's still opened, so I don't think that digging
it up should be a problem.
I agree with kissifrot about specific case - both values convert to "(int)2147483647", at
least on 32bit system, which is nowhere near to "00001000010000000198358".
Though, I can't agree with drm. There is a reason for having two types of comparisons - if you
are sure that you don't need values to be converted, just use strict comparison.
I agree that there are cases when numerical strings need to be compared as strings, but there are
also lots of cases when numerical strings have to be compared as integers. For example, some
functions that return data from DB, return integers as strings, which may be compared to data from
browser, which by default is also string, but comparison needs to work like if they were numbers.
------------------------------------------------------------------------
[2011-02-17 08:58:37] kissifrot at gmail dot com
I agree with that, for example if I have
$ric1 = '00001000010000000198358';
$ric2 = '00001000010000000198455';
var_dump($ric1 == $ric2)
should return false, not true, just because it's logical.
But the current behavior makes PHP somewhat unreliable :(
------------------------------------------------------------------------
[2008-09-06 23:49:58] drm at melp dot nl
Though documented (http://www.php.net/language.operators, quote "If you compare two numerical
strings, they are compared as integers."), this is indeed unexpected behaviour (and thus a bug)
This bug will probably be closed and denoted as "sorry, documented feature", but I think
this is really a candidate for revision in any next major PHP version.
Comparison should always feel intuitive, and PHP has made the move towards more "secure"
defaults. This falls (imo) under the same category. Please witness following example.
client side code:
<form ...>
<input type="radio" value="0" name="selection" /> No
selection
<input type="radio" value="whatever" name="selection" />
whatever selection
(...)
</form>
server side code:
if ( $_GET['selection'] == 0 ) {
echo '<p>Please make a selection!</p>';
} else {
// process request
}
Though the example does not imply any security issues, they are not unimaginable. Please reconsider
the behaviour of the comparison operator.
My suggestion:
Implement (and document!) the following:
Any left side of the comparison is only cast to number if the right side doesn't fail to.
Casting to number is considered successful, if and only if the string would syntactically be a
number in the PHP
Therefore, the string should match the following:
http://php.net/language.types.integer
http://php.net/language.types.float
[At both pages, see the "formal" definition of both types.]
In any OTHER case, the comparison should act as follows:
If ANY of the sides is of a string type (and of course fails to cast to number), the other side is
cast to string, causing the types to follow these rules:
integer: the string representation of the integer (e.g. "0", "-4" or
"123")
float: the string representation of the floating point number, represented in one and only one
particular format, preferably just the %.f format.
boolean: cast to integer, cast to string (so true becomes 1, becomes "1"; false becomes 0
becomes "0")
array: "array" causing a notice
object: "object" causing a notice, or calling the __toString method if defined.
The oppposing problem is a non-generic way of handling any other comparison. As a rule, we could
state that any other comparison -if both sides of different type- is handled the way it is in the
current PHP version. If they are of the same type, the == operator should act the same as the ===
operator.
This is, as i am very sure, easily realized.
Please do not hesitate to ask me any questions through mail.
------------------------------------------------------------------------
[2007-11-15 16:27:02] ken at smallboxsoftware dot net
Description:
------------
Casting during comparison should only happen if values of different types are being compared.
For example: "42" == "+42" should not return true.
This result is not very intuitive and probably leads to a number of subtle errors in various
scripts.
Reproduce code:
---------------
<?php
echo "Should Return False:".("400" == "+400")."<BR>";
echo "Should Return False:".((string) "400" == (string)
"+400")."<BR>";
echo "Does Return False:".("400" === "+400")."<BR>";
?>
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=43304&edit=1