I was reading an article and I found this example:
// Prints bool(true)
var_dump('9223372036854775807' == '9223372036854775808');
// Prints bool(false)
var_dump('9223372036854775807' ==='9223372036854775808');
Anyone can explain me why?
From reddit and a php bug report.
A few things are happeing here.
== doesn't return false if the values are of different type. In this case PHP is converting the strings to floats to compare the numbers and due to thier size and the way PHP handles floats they are rounded to the same number, hence comparing the 2 strings as numbers they are the same.
=== enforces type must be same. So comparing those two as strings they are not the same.
As mentioned by #Classified in another comment this was fixed in php 5.4.4 so isn't a current bug.
The both cases should return FALSE because the numbers are different, but I think your doubt is about The difference between '==' and '===' AND why first case returns true right ?
When you use the '==' you're comparing if the values are equals BEFORE type-juggling, when you use the '===' you're comparing if the values equals AFTER type-juggling.
In another words, when using '==' you're comparing if values are equals, but when you're using '===' you're comparing if values and types are equals.
In these cases, both comparisons should return FALSE because the values are different, but about the first comparison returning TRUE, it is a bug in PHP, as you can see in: https://bugs.php.net/bug.php?id=54547
PS: 9223372036854775807 is the bigger int number, so if you check types with gettype(), you will see:
9223372036854775807 is an integer.
9223372036854775808 is a double.
As of PHP 5.4.4 this is no longer an issue.
The reason why this is happening, is because of type-juggling. In the first example you're checking if the two values are equal AFTER type-juggling so effectively it's comparing two string types.
And in the other example you are checking whether the two values are identical, as in the same type and the exact same value.
Check this.
<?php
var_dump('9223372036854775807' == '9223372036854775808');
var_dump('9223372036854775807' ==='9223372036854775808');
Output:
bool(false)
bool(false)
It doesn't. See your exact code above running here for proof https://3v4l.org/4oHvo
UPDATE:
Based on the below comments, it looks like the person asking is using a version of PHP that is 4 years old and no longer supported, and potentially vulnerable to security flaws. Update your PHP!
Please see the End of Life chart on php.net https://secure.php.net/eol.php
Related
Can someone explain why the following two statements return true?
if ('0e368798' == '00000000')
or
if ((string)'0e368798' == (string)'00000000')
Why do I have to use the strict operator to check the equality of these two strings?
Because XeY is X * 10^(Y), and 0 times anything is 0. 0000000 is also 0. And == in PHP very intuitively thinks that if it can be converted into a number, it should be.
EDIT: It was in a helpful comment that is now deleted, so with apologies to the commenter whose name I did not catch, I will repeat it here - from PHP docs on comparison:
If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically. These rules also apply to the switch statement. The type conversion does not take place when the comparison is === or !== as this involves comparing the type as well as the value.
I browsed through several similar questions, but they all only state the fact:
If ... comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically.
Okay, I got it. It explains what is going on when '00001' == '1' returns TRUE.
The question is: Why PHP does so?
What is the reason for probing strings for being numeric, and then casting if so? Why can't we just compare two strings already?
I can fairly understand what casting is required if two operands has different types. But why it does "usual math" when both are strings?
You can compare two strings.
"00001" === "1" // false
Remember == means equivalent === means equal
My only guess as to why this is the case is because in the beginning PHP strived to be a type-less language before they went the route of becoming a loosely typed language.
PHP was originally string processor that allowed for a little scripting inside of it. Since all inputs on the web are textual in nature it had to work hard given textual input to behave sanely when it came to dealing with numbers.
I could be wrong about this but I don't believe the ability to explicitly cast data types entered the stage until PHP 4 with the introduction of the *val functions (like intval) etc. and I think the casting notation, like (int) came around after that.
For the non comparison operations it was pretty easy because they all have a type associated with them (+ - / * all deal with numbers whereas . deals with strings) so a clear path to how things should be cast in those cases is apparent.
But with equality or equivalence checks between variables then the only way to do that was to treat everything that looked like a number as a number because at the time the only way it could be gotten would be by externally would be as a string and there was no way to make it otherwise.
Because, PHP produce a product for End-Users, not for Application Developers.
So when you produce such product like below:
if (isset($_POST['submit'])){
if ($_POST['myinput'] == "1") echo 'Yes'; //or == 1
else echo 'NO';
}
?>
<form name="myform" method="POST" action="">
<input name="myinput">
<input name="submit" type="submit">
</form>
If the user enter 1 or 0001, what do you expect to print in both case? Yes or NO?
the answer is clear. we expect to see Yes. so this is why PHP does so
If for any rare reason, we need to definitely compare them, then we should change == to ===
Ah, finally I got it. It was quite stupid of me.
Comparison involves not only "is equal" but also "less than" and "greater than". And for the latter two it is obviously critical to cast numerical operands before comparison, because numbers often being represented in PHP as strings, and 11 have to be greater than 9 even if both stored in strings.
So, as compare_function() does all the comparisons at once, returns either 1, 0, -1 to tell if first operand is bigger, equal or less than second respectively - well, it's fairly explains, why operands being cast.
I was just debugging a script and found that an if-statement wasn't working the way I expected it to.
var_dump("6064365413078728979" == "6064365413078728452");
die();
The code above will result in the following:
bool(true)
With the === operator it works as expected. Anyone got any ideas why?
I'm using PHP Version 5.3.13 with a wamp installation on a x64 windows machine.
PHP has loose type comparison behavior, so your numerical strings are getting converted to integer types before == non strict comparison, and the conversion result is overflowing.
That is the principal reason to use === when it's possible.
Take a look at this page for further details on type juggling.
<?php
$a=6064365413078728979;
$b=6064365413078728452;
echo $a."<br>".$b;
//var_dump( $a==$b );
die();
?>
When you run that, then on your machine that might be exceeding limit for a number and that is a numeric comparison taking place. Try the script above and see value for $a will probably be different than the value you gave.
That is why when both are compared numerically they are equal. Hence use === as suggested by others
Edit: Explanation based upon #Axel's Advice.
PHP Manual explains
The size of a float is platform-dependent, although a maximum of
~1.8e308 with a precision of roughly 14 decimal digits is a common
value (the 64 bit IEEE format).
And this website is offering and explanation on the Overflow phenomenon and a small php code to test your system's integer and float range. Getting to know the limit on your servers will most probably explain it best why the offerflow occured
It seems that simple comparison signs >,>= and their reverse components can evaluate if a certain variable is a number or not. Example $whatami='beast'; ($whatami<0)?echo 'NaN':echo 'is numeric!';
Are there cases where is_numeric() usage is necessary for positive values (number >0)? It seems that using comparison signs above would determine if the variable is numeric..
As I have been finding out, a lot of these helper functions are really necessary because PHP isn't strongly typed. I posted a similar question (although not that similar) about isset earlier this week. One thing to note is that PHP will change your string to its integer value for comparisons during some instances (when there are mixed types). This can't be overlooked. I think this is a strong case for is_numeric
from PHP Manual
If you compare a number with a string
or the comparison involves numerical
strings, then each string is converted
to a number and the comparison
performed numerically. These rules
also apply to the switch statement.
The type conversion does not take
place when the comparison is === or
!== as this involves comparing the
type as well as the value.
Another thing to think about is that "what is 0" in PHP. It means a lot. It's not always numeric. It may be a numeric string, boolean false, integer, etc... This is why those helper functions exist.
To add to my answer:
change your example:
$whatami='beast';
($whatami<5) ? echo 'less than 5' : echo 'more than 5';
PHP would change 'beast' to its integer equivalent and then do the comparison. This would give unintended results. If you really wanted something similar, you'd have to wrap it in another conditional:
$whatami='beauty';
if(is_numeric($whatami){
($whatami<5) ? echo 'less than 5' : echo 'more than 5';
} else {
exit('what, am I not pretty enough for a beast?');
}
Then you would get your intended result (as weird as it may be).
There is a big difference between "can evaluate if a certain variable is a number or not" and "evaluate if a certain variable is a positive number". Using the comparison signs require you to test it twice (Both > & <= or >= & <) and may not be immediately obvious. is_numeric means you only need a single test and makes it quite obvious what you are doing.
Also, a string will evaluate as 0, meaning it throws your idea out. Stick with the proper commands :)
As per comment: Well, in this case, you are asking for comparing is_numeric against a test for positive numbers, excluding 0. This is not the intent for is_numeric, so naturally it may not be necessary. If you do a mathematical check that involves 0 as the answer or as part of the range, you will need is_numeric, otherwise you won't need it. The first part of your question asks a different question, so:
It seems that simple comparison signs >,>= and their reverse components can evaluate if a certain variable is a number or not - Incorrect
Are there cases where is_numeric() usage is necessary for positive values (number >0)? - No
It seems that using comparison signs above would determine if the variable is numeric - No. They can determine if a variable is either a non-zero number or unknown, not numeric.
Comparison will depend on the type of data on the left side of the operator.
The important thing to remember is that PHP is not a strongly typed language. If you want to compare a number and ensure it is a number, then yes, is_numeric() would be a good check. For example,
echo (is_numeric($whatami) && $whatami < 0) ? 'number greater than zero' : 'NaN or negative';
However, this shouldn't be generalized. If you can comment more on what you are wanting to do, you may find a more detailed answer.
Yes, there are cases.
For instance:
var_dump("5aa" > 4); //bool(true)
var_dump("5aa" > 6); //bool(false)
As you can see, the conversion of "5aa" to int(5). Let's see what is_numeric gives:
var_dump(is_numeric("5aa")); //bool(false)
So, is_numeric is more strict. Whether it's necessary depends on your application.
Notice that are cases where a numeric string and a number are not exactly the same thing:
var_dump("255" & "2"); //string(1) "2"
var_dump(255 & 2); //int(2)
See bitwise operations:
Be aware of data type conversions. If both the left-hand and right-hand parameters are strings, the bitwise operator will operate on the characters' ASCII values.
I just reduced a crazy bug to what's in the title of this question.
I'm sure there's a Perfectly Reasonable Explanation for why Php thinks that 0 == '%' (or any other special character, I think).
I thought it would be good to get that explanation on StackOverflow!
It will do the same to any string, converting a non-number string to integer always gives 0.
Using '===' (for exact, literal comparison -- the values must be the same type and also equal) instead of '==' solves this problem. With '==' it's trying to cast '%' to a number and 0 is the best it can do.
In the event that a strict comparison operator is not directly suitable, if you want both values to be compared as strings, you can use strcmp(). An example could be where both values are variables, and the types might be either string, or int. Instead of type casting to string and then using strict equality check, strcmp() can be less verbose.
php's type coercion is very convenient. But if you don't understand its many rules(some can bite), you should try to avoid using it. See
http://www.php.net/manual/en/types.comparisons.php
since '%' isn't true, it ought to be false (0), so of course 0=='%'
;-) funny though
This is because it converts '%' to number and it is 0.
The way, however, how PHP converts strings to numbers is pure evil IMHO, because non number string does not have to result in zero.
If it starts with a digit then php will result the first number it can find in it and ignore the rest of the string. So:
"2 times 5 equals 10"
..will result in 2 when casted to a number.
Article in the documentation