views:

284

answers:

5

In one bit of code I'm working on, I need to pull a value from the database and check if it is 0. Originally, I had written this as:

if ($myVal == 0) { ...

But when I looked at it again today, I realised a bug there:

var_dump("foo" == 0);  // bool(true)

// and while we're here...
var_dump(intval("foo")); // int(0)

Since this value is coming from the database, that usually means it will be a string, so I suppose I could do this:

if ($myVal === "0")

but it seems counter-intuitive since I actually want to be dealing with an integer, and this would appear to show that we're working with strings. (I hope that makes sense to you.) Also, it shouldn't be unexpected that any given DB accessor would cast values to their appropriate type, given the field type.

What method do you use to check for a value of 0 when it could be a string or an int?

+2  A: 

The best I've got currently is this:

is_numeric($myVal) && $myVal == 0
nickf
This condition will always return false, since as you said in your question, values from db are returned as strings.$myVal is a string, and the comparison will stop here.You should cast your value to an integer before to do the comparison.
Boris Guéry
Actually bgy, is_numeric() will return true for a string of a numeric value. See http://au2.php.net/is_numeric
thomasrutter
A: 

Try using intval() to cast the string to an int

if( intval($myVal) == 0 )
Josh Curren
(intval("this shouldn't equal zero") == 0) is true
nickf
-1: intval('null') returns 0
ya23
Casting a string to an int results in 0 unless the string begins with digits. The string "foo" casts to 0, the string "35foo" casts to 35.
dirtside
+9  A: 

Short version:

if ("$myVal" === '0')

or

if (strval($myVal) === '0')

Long version:

if ($myVal === 0 || $myVal === '0')
cletus
oh that's clever - i wouldn't have thought to convert it the other way!
nickf
My guess is that the long version is actually the faster version. === is a fast comparison because it does no type conversions.
jmucchiello
@Jm: you're probably right. It's just more annoying to type. :)
cletus
I've just done some benchmarking: in terms of running time, your strval() method is pretty much equal to the is_numeric function I proposed (0.31s to do 100,000 iterations). However, using the "$myVal" === 0 method is about 6-7 times faster, and the long version is over 10 times faster!
nickf
I'm honestly surprised that "$myVal" is way slower than strval(). I would've expected it to be the other way around. Interesting results.
cletus
A: 

If the values you get back from the database are strings, but the original datatype is integer, then you probably want your DAO (Data Access Object, or whatever it is that's pulling the data) to cast things to data types you expect. That way, the PHP code that's looking at the values is looking at the data type it expects.

The trouble is, of course, that there isn't a 1-1 correspondence between the data types the DB defines, and the data types PHP defines. However, for the most part this isn't a problem, since there's equivalent types for most of the types we use normally: int, float, bool, string.

The upshot is, that between the place where you query the database, and the place where you check those values, those values should be cast to the data types you expect. I just tested with mysql_fetch_object() on a MySQL table containing an int(10) and a varchar(50); both fields always were pulled in as type "string" by PHP. So if you want one of the fields treated as an int, cast it to an int before you do anything with it. For example:

$rs = mysql_query("SELECT * FROM table");
while ($row = mysql_fetch_object($rs)) {
    $RealRow->id = (int)$row->id;
    $RealRow->name = $row->name;
    // etc.
}

// ... later ...

if ($RealRow->status == 0) {
    // do something
}

The query and RealRow stuff should be inside a class/method, so that it's encapsulated; that way, ANY part of your code that gets data from table will always get the $RealRow object instead, which will have everything set to the proper data types. Of course, if you change your data types, this requires manually editing the DAO to deal with the casting; it would also be possible to query the DB to get the type of each field (with a "SHOW COLUMNS FROM table"), and automatically cast the fields to the proper data type.

dirtside
The "SHOW FULL COLUMNS FROM myTable" command is a much easier way to determine the data types of each field. Sometimes, however, this level of abstraction can be over-the-top for a given situation.
nickf
I'd prefer if "SHOW [FULL] COLUMNS" actually broke down the data types by basic type, display space, unsigned, etc. into separate fields, so that it was more programmatically accessible. Right now you have to manually parse the "Type" field of the output... although I'm sure someone's got a library for that.
dirtside
A: 

I think you should just use

if ($myVal == 0)

I don't think it's necessary to worry about whether $myVal is "foo". You've said yourself that this value is only ever going to be a number.

In other words, if you ever experience $myVal being "foo", the bug is not that "foo" == 0, the bug is that $myVal is "foo", when it's supposed to be a number.

thomasrutter