Weird behaviour with if statement - php

The following appears to work, yet I really don't think it should:
if ("'True','False'" == 0)
{
echo 'Hello, World.';
}
Is it grepping the last False out of the string, and if so why, and how do you stop it?

This is due to loose typing. When you compare a string to a number, PHP has to cast one to the other's type. In this case, the string, when casted to an integer, is worth 0, your condition being True.

Any string evaluates to 0 when being compared against a number (unless it's a stringed number such as "5" or "4string"). That's why it'll always evaluate to 0.
See the Type Comparison Table

What's really happening is that PHP is trying to do an implicit type conversion, and for one reason or another it's deciding that string when converted to an integer looks like 0. You can prove this to yourself by doing:
echo ((int) "'True','False'");
If you want to do a type-checked comparison you should use the triple equals (===):
if("'True','False'" === 0)
...which will most certainly evaluate to false.

No; it's converting the string "'True','False'" to a number — and that number is 0. 0 == 0 is true. You can solve it by using !"'True','False'" if I understand your intent correctly, or by using strict equality, ===, which you should generally use.

Related

PHP : confused with "==" operator

Can somebody explain to me why this codes returns "TRUE".
I know that i should use the "===" rather "==" but I run to this code and wondering why it returns to true. Thanks in advance.
<?php
$s = "final";
$i = 0;
if($s == $i){
echo "TRUE";
}else{
echo "FALSE";
}
When you are trying to compare string and number, interpretator converts your string to int, so you got 0 == 0 at final. Thats why string == 0 is true.
Take a look at the PHP comparison tables.
You can see in the "Loose comparisons with ==" table that comparing the number 0 with a string containing text ("php" in the example) evaluates to TRUE.
This is just a property of the loose comparisons implemented in PHP. I wouldn't search for any more logic behind this than that this is a given.
As mentionned above, it is an issue with php's loose comparison. The accepted answer on php string comparasion to 0 integer returns true? Explains it well enough IMHO. in short "==" attempts to cast your string into an int, and since it fails, the resulting int has a value of 0
From PHP comparison operators:
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.
And from PHP string conversion to numbers:
The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero).
So when you compare integer and a string, PHP tries to convert string to integer first and as "final" doesn't contain any valid numeric data, it is converted to 0.
You can try:
var_dump( intval('12final') ); //int(12)
var_dump( floatval('1.2final') ); //float(1.2)
This is because of both 12final and 1.2final start with valid numeric data (12 and 1.2 respecrively), their converted value is not 0.

php string comparison unexpected type juggling

I encountered a strange and unexpected behavior in PHP while comparing some string values. The first two statements below return true when I would expect them to return false. The last statement returns false as expected. I'm aware of PHP's Type Juggling, but what I understand from the docs is that type juggling happens when you are comparing two different data types like a string and an integer. In the examples below though both literals are strings. Does this mean that when you are doing string comparison in PHP it inspects both strings to see if they look like integers and if so type casts the both of them to integers and then compares those integer values. So my question is under what conditions does this behavior happen, how exactly does string comparison work in PHP?
var_dump("10" == "10.0000");
var_dump("10" == "+10.");
var_dump("10" == "10 ");
#output
bool(true)
bool(true)
bool(false)
Updates
So baba's answer below comparison involves numerical strings really helped in getting me to understand what's going on. The function is_numeric will return to you whether or not a string is considered to be a numeric string. interestingly "10 " is not considered a numeric string but " 10" is. I dug around the PHP source code and I believe the implementation of is_numeric is in the is_numeric_string_ex function. From that one can tell exactly when PHP will treat a string as a numeric string.
You are getting error because of the position of the space this would return true
var_dump("10" == " 10"); // true
So if you RUN
var_dump("10" == "10 "); //false
What you are actually Running is because it would be treated as a string
var_dump("10" == 0); //false
This is because Type juggling would convert "10 " to 0 this is in the PHP Documentation
FROM PHP DOC
TRUE if $a is equal to $b after type juggling.
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.
If you want to trick type juggling
var_dump("10" == 0 + "10 "); // true
This is Because
An example of PHP's automatic type conversion is the addition operator '+'. If either operand is a float, then both operands are evaluated as floats, and the result will be a float. Otherwise, the operands will be interpreted as integers, and the result will also be an integer. Note that this does not change the types of the operands themselves; the only change is in how the operands are evaluated and what the type of the expression itself is.
I suppose the definite answer lies buried somewhere in the vastness of
compare_function
in php-src/Zend/zend_operators.c and the macros used in there.
In this case, all the 'strings' except the last one, are treated like floats or integers, and then compared. Thats why line 1 and 2 give a true.
In line 3 there is a space in the string, and that means for php that is is a 'real' string, and that line gets strings compared.
I do not like loose typed languages either, but for php this is the way it works.

Is this a PHP bug ("false" == 0)?

if ("false" == 0) echo "true\n";
// => true
While PHP documentation says:
var_dump((bool) "false"); // bool(true)
If it is a bug where can I file it?
Nope, not a bug. Don't bother filing it.
This seemingly inconsistent behavior has nothing to do with the word "false". It has to do with your string consisting of only letters and no numeric digits, so when it gets cast to an integer for comparison (== 0), it results in 0, making 0 == 0 which evaluates to true.
If you compare any other alphabetic string to 0, you'll get the same result:
"abcd" == 0
"a" == 0
"true" == 0
It is not a bug, it's a well documented feature when comparing values of different datatypes - in this case, string to integer. PHP converts the string to an integer to do the comparison, and "false" converts to 0.
See the 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.
and this page on string to number conversion
If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero).
To avoid this behaviour, use comparison with strict typing:
if ("false" === 0) echo "true\n";
The problem is that PHP casts variables unless you use a strict comparison. As others mentioned, the string "false" is being cast to an integer.
If you want to do a comparison without typecasting use:
"false" === 0
This might help: These are the only things that PHP considers false:
Actual boolean false
NULL values (empty)
The Integer 0
Try to avoid string comparisons of text and stick with booleans!

PHP Bug with Conditional Operator?

$i=0;
$j='00:15';
if ($i==$j)
echo "equal";
else
echo "not equal";
displays equal?
00:15 is cast into an integer first and then compared with $i. Since intval() (which does the casting) stops at the first non-numeric character, 00:15 is cast into zero, which is equal to zero. No bug here, this is how the == operator works.
If you want to avoid casting, use === instead.
Using the == the types will be converted before they are compared. In this case, both will be converted to an integer, and when you convert a non-numeric string to an integer, it will probably result in 0.
If you use the === operator instead, you will get the result that you expect.
string and int compares as int's, So $j converts to 0 here because starts with 00
Not bizarre at all - when comparing string with integer, the first one is being cast to integer then compared. Use === for type checking and you'll see the real result
Turns out the === is problematic
for example 10===10 will be false if one is integer and one is string even though they are identical as can happen from forms posting.
the solution i used was:
if ("$i"=="$j")
this way it just checks if they're identical regardless of type

Very illogical php value comparisons

I stumbled upon a very strange bit of PHP code. Could someone explain why this is happening? *****BONUS POINTS***** if you can tell my why this is useful.
<?php
if(0=='a'){
print ord(0)." should NEVER equal ".ord('a')."<br>";
}
if(false==0){
print "false==0<br>";
}
if('a'==false){
print "a==false<br>";
}
?>
And the resulting output:
48 should NEVER equal 97
false==0
In PHP, 'a' is not the ASCII character a, but the string a. In a numeric context, it is equal to 0. For instance intval('a') results in a value of 0.
This is useful because PHP is primarily used for processing text, and one might want to try the test (123 == '123'), which is true. And given that a number in single (or double) quotation marks is treated as the number, it doesn't make sense for a string with no numeric value to be treated as anything other than 0.
Oh yeah, one more thing. 'a' in a boolean context is true, not false. I believe this makes some types of text processing more natural, but I honestly can't think of an example at this late hour.
Well, there's always the PHP type cheat sheet for that!
This is a basic principle of weakly/dynamically typed languages called type juggling. Types will be cast to other types in certain circumstances. When you compare a string to a number, the string will be cast into a number. When comparing anything to a boolean, that value will be cast to a boolean.
There are rules for every type as to how it will be cast into another type or how it compares to other types. 'a' happens to be converted to 0 when cast to a number (the only logical choice, really). To avoid this type casting, test not with the equality operator ==, but with the identity operator ===.
As James pointed out, this is useful since PHP deals a lot with strings that are really numbers. For example, HTML forms only submit strings, even if the value is a number. It also allows for some really terse code, like:
$result = someOperation();
if (!$result) {
// $result may be null, false, 0, '' or array(),
// all of which we're not interested in
error();
}
It also means you have to be really careful about what to check for in which circumstances though, since a value might unexpectedly cast into something else. And admittedly, 'a' == 0 in itself is really a pitfall of type juggling rather than helpful. It's one of the situations where you have to be careful and test like if (is_numeric($var) && $var == 0).
ord() takes characters, so PHP turns 0 into '0'. And 0 is equal to false, even though it is not identical (===).
Check out the PHP type comparison tables from the manual. It's a really handy thing to have close at hand until you've internalised it and has been invaluable to my understanding of exactly what will evaluate to true and when.
Others have already answered the core of the question, but I think it's important to state that in PHP, the only non-empty string that does not evaluate to "true" with the == operator is "0" as PHP treats any string containing only numbers as an integer or float.
The rationale for this is that PHP is fairly loosely typed and tries to allow integers, strings, floats and boolean values to be interchangeable. A real-world and extremely common example of this is if you're using the mysql or PDO functions, strings are returned for everything, even if the underlying column is an integer.
Consider the following sql:
CREATE TABLE `test`.`pants` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`some_other_int` INT NOT NULL
) ENGINE = InnoDB;
INSERT INTO `test`.`pants` (`id`, `some_other_int`)
VALUES ('1', '1'), ('2', '0');
And the following code:
<?php
$c = mysql_connect('127.0.0.1', 'user', 'password');
mysql_select_db('test', $c);
$r = mysql_query('SELECT * FROM pants', $c);
while ($row = mysql_fetch_assoc($r)) {
var_dump($row);
foreach($row as $k=>$v) {
if (!is_string($v))
echo "field {$v} was not a string!\n";
}
}
The "field x was not a string!" message is never printed, even though every column in the database is an integer. Suppose you want to actually use the second row in that table.
<?php
$id = 2;
$r = mysql_query(sprintf('SELECT * FROM pants WHERE id=%s', mysql_real_esacpe_string($id)), $c);
$row = mysql_fetch_assoc($r);
// this is the important bit
if (0 == $row['some_other_int']) {
echo "It was zero!";
}
If the string "0" was not treated as the integer 0 for the comparison, the above code would never print "It was zero!". The programmer would be required to take responsibility for juggling the type of the value which comes out of the database. This is not desirable for a loosely typed language.
Strict equality including type is tested using the "Is really, truly, honest to god equal to" operator, which is represented by the symbol "===".
I don't see how ('a'==0) is helpful
$var = '123abc';
if (123 == $var)
{
echo 'Whoda thunk it?';
}
It comes down to PHP's implicit conversion rules.
I'm failing at thinking of a practical example, but that's the basic reason why you're seeing that behavior.
Expansion:
In your example, 'a' is converted to 0 (zero), for the comparison. Imagine that for the purpose of the comparison, it's equivalent to '0a'. (That's the numeral zero, not the letter 'o.')
Further expansion:
I thought there was a good example use case for this in the manual, but I failed to find it. What I did come across should help shed some light on this "illogical" situation.
PHP is first and foremost a Web
language, not a general-purpose
scripting language. Since the Web is
not typed and everything is a string,
I had to do things slightly
differently early on to make PHP do
what people expected. Specifically,
"123"==123 needs to be true in order
to not have to type cast every single
numeric user input.
http://bugs.php.net/bug.php?id=48012
That doesn't exactly answer the question, but it points in the general direction.
PHP is a loosely typed language, and allows you to compare values of different types without throwing errors, which makes it very easy to use but as you have found can cause some weird but logical outputs.
Your first example:
if(0=='a'){
print ord(0)." should NEVER equal ".ord('a')."<br>";
}
When two different types of values are compared, one value is first turned into the same type as another via a cast and then compared. In the example of Int and String the string is converted into Int. When PHP turns a letter into a string it takes all the first numeric characters and then chops of the rest: i.e '123123afraa' becomes 123123, '9a9' becomes 9. If the string does not start with numerals it is given the value of 0.
Therefor your example is really: 0===(string)'a' which is really 0===0 since 'a' does not start with a numeric. I think you were expecting PHP to return the value of 'a' in ASCII which it does not! This is really useful to sanitise strings, php rarely needs to deal with ascii values it is too high level for that. (Its for making websites!)
When a string is compared to a boolean a value of '' or '0' are false, all other values are true. This is useful so you can check if a value is 'empty':
url http://domain.com/?foo=
if ($_GET['foo']))
{
// do something
}
When an integer is compared to a boolean the values of 0 is false other values are true, this is pretty standard.
So, all in all you need to understand what happens when different types of variables are compared with the == operator. Also it is probably wise to realise that == is almost never what you want and using === (which will not typecast your values) is ALOT safer.
The code seems to emanate from a unit test for the purpose of catching failures, hence the seemingly weird comparisons. In the same light, it may be preparatory to the main unit test to confirm that the == operator is working properly - as it should.

Categories