I have the following piece of code:
$item['price'] = 0;
/*code to get item information goes in here*/
if($item['price'] == 'e') {
$item['price'] = -1;
}
It is intended to initialize the item price to 0 and then get information about it. If the price is informed as 'e' it means an exchange instead of a sell, which is indicated with a negative value because it is to be stored in a database which requires a numeric value.
There is also the possibility to leave the price as 0, either because the item is a bonus or because the price will be set in a later moment.
But, always when the price is not set, which leaves it with the initial value of 0, the if loop indicated above evaluates as true and the price is set to -1. That is, it considers 0 as equal to 'e'.
How can this be explained?
Edit: When the price is provided as 0 (after initialization), the behavior is erratic: sometimes the if evaluates as true, sometimes it evaluates as false.
you are doing
==
which sorts out the types for you.0
is an int, so in this case it is going to cast'e'
to an int. Which is not parseable as one, and will become0
. A string'0e'
would become0
, and would match!use
===
There's a rather handy method in PHP for validating a mix of "0", "false", "off" as == false and "1", "on", "true" as == true which is often overlooked. It's particularly useful for parsing GET/POST arguments:
It's not wholy relevant to this use-case but given the similarity and fact this is the result search tends to find when asking the question of validating (string)"0" as false I thought it would help others.
http://www.php.net/manual/en/filter.filters.validate.php
You should use
===
instead of==
, because the ordinary operator does not compare the types. Instead it will attempt to typecast the items.Meanwhile the
===
takes in consideration type of items.===
means "equals",==
means "eeeeh .. kinda looks like"Your problem is the double equal operator, which will typecast the right member to the type of the left. Use strict if you prefer.
Let's go back to your code (copied above). In this case, in most cases, $item['price'] is an integer (except when it is equal to e, obviously). As such, by laws of PHP, PHP will typecast
"e"
to integer, which yieldsint(0)
. (Don't believe me?<?php $i="e"; echo (int)$i; ?>
).To easily get away from this, use the triple equal (exact comparison) operator, which will check the type and will not implicitly typecast.
P.S: a PHP fun fact:
a == b
does not imply thatb == a
. Take your example and reverse it:if ("e" == $item['price'])
will never actually be fulfilled provided that $item['price'] is always an integer.This is due to how PHP does the comparison operation that the
==
comparison operator denotes:As the first operand is a number (
0
) and the second is a string ('e'
), the string is also converted to a number (see also table Comparison with Various Types). The manual page on the string data type defined how the string to number conversion is done:In this case the string is
'e'
and thus it will be evaluated as a float:As
'e'
does not start with a valid numeric data, it evaluates to float0
.evaluates
true
because"ABC"
is converted to integer and becomes0
then it is compared to0
.This is an odd behaviour of the PHP language: normally one would expect
0
to be promoted to string"0"
and then compared to"ABC"
with a resultfalse
. Perhaps that's what happen in other languages like JavaScript where the weak comparison"ABC" == 0
evaluatesfalse
.Doing a strict comparison solves the problem:
evaluates
false
.But what if I do need to compare numbers as strings with numbers?
evaluates
false
because the left and right term are of different type.What is actually needed is a weak comparison without the pitfalls of PHP type juggling.
The solution is to explicit promote the terms to string and then do a comparison (strict or weak doesn't matter anymore).
is
true
while
is
false
Applied to the original code: