Type Juggling and Strict Comparisons
A helpful friend who "fixes" your spelling without asking is lovely most of the time, and baffling some of the time. PHP converting types for you is the same.
In Data Types, you saw that every value has a type. But PHP doesn't make you keep them apart. Mix a string and a number, and PHP quietly converts one of them to make the operation work. That's called type juggling.
It's convenient: form data always arrives as strings, and PHP lets you do math with them anyway. But it has sharp edges. This lesson shows where they are, and how to avoid them.
Numbers inside strings
When you use a string in math, PHP tries to read it as a number:
<?php
var_dump("5" + 3);
var_dump("1.5" + 1);int(8)
float(2.5)A string that's entirely a number, like "5" or "1.5", is called a numeric string, and PHP converts it without complaint.
A string that only starts with a number gets converted too, but with a warning, since it's probably a mistake:
<?php
var_dump("5 apples" + 3);
// error: Warning: A non-numeric value encounteredThe result is still int(8). PHP used the 5 and ignored the rest.
And a string with no number at the start stops the script with an error:
<?php
var_dump("apples" + 3);
// error: Uncaught TypeError: Unsupported operand types: string + intOlder PHP (before version 8) turned "apples" into 0 silently. You'll still find old tutorials that say so.
Loose comparison ==
The loose == converts types before comparing. That's where most of the surprises live:
<?php
var_dump(5 == "5");
var_dump("1" == "01");
var_dump("10" == "1e1");
var_dump(null == false);
var_dump("0" == false);
var_dump("abc" == 0);bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)"1" == "01": both are numeric strings, so PHP compares them as numbers, and 1 equals 1."10" == "1e1":1e1is scientific notation for 1 × 10¹, which is 10.null == falseand"0" == false: both sides count as false (more on that below)."abc" == 0: false in PHP 8. (In older PHP, this was true, which caused real security bugs.)
Imagine comparing two product codes, "1e1" and "10", with ==. PHP says they're the same product! That's why the advice from Operators and Expressions stands: use ===, which never converts.
<?php
var_dump("1" === "01");
var_dump("10" === "1e1");
var_dump(null === false);bool(false)
bool(false)
bool(false)Truthy and falsy
In an if or with !, &&, and ||, PHP converts values to booleans. These values count as false (they're called falsy):
| Value | Why |
|---|---|
false | it's false |
0 and 0.0 | zero |
"" | an empty string |
"0" | a string containing just zero |
null | no value |
[] | an empty array |
Everything else counts as true (truthy), including some surprises:
<?php
var_dump((bool) "0");
var_dump((bool) "0.0");
var_dump((bool) " ");
var_dump((bool) "false");bool(false)
bool(true)
bool(true)
bool(true)"0" is falsy, but "0.0", a single space, and even the word "false" are all truthy, because they're non-empty strings that aren't exactly "0".
This matters with forms. If someone types 0 into a "how many tickets?" box, the value arrives as the string "0", which is falsy. A check like if ($tickets) would treat it as if nothing were typed. You'll see safer checks in Validating and Escaping User Input.
Converting on purpose: casting
Instead of letting PHP guess, you can convert a value yourself with a cast: the type name in parentheses, before the value:
<?php
var_dump((int) "42");
var_dump((int) "12abc");
var_dump((int) "abc");
var_dump((int) 9.99);
var_dump((float) "3.5");
var_dump((string) 7);
var_dump((bool) 0);int(42)
int(12)
int(0)
int(9)
float(3.5)
string(1) "7"
bool(false)Notice (int) 9.99 gives 9. Casting to int cuts off the decimals; it doesn't round. For rounding, use round().
Also notice that a cast never complains: (int) "abc" quietly gives 0. That's handy, but it means casting alone can't tell you whether the input was a real number. To check first, use is_numeric():
<?php
var_dump(is_numeric("42"));
var_dump(is_numeric("4.2"));
var_dump(is_numeric("42 cats"));bool(true)
bool(true)
bool(false)The rules of thumb
- Compare with
===and!==. - When a value comes from outside, like a form, check it (
is_numeric) and then convert it (a cast) yourself, rather than letting PHP juggle. - Remember that
"0"is falsy. - When you're unsure what a variable holds,
var_dumpit.
Try it
A quiz app checks some answers that arrived as strings. Predict each line.
Running PHP here
Running PHP right in the browser is coming to Syntaxia soon. For now, you can read and edit the code here. If you have PHP installed on your computer (see Setting Up), save it as index.php and run it with php index.php.
Check your prediction
bool(true)
bool(false)
bool(true)
No tickets
bool(true)
bool(false)
int(3)
bool(true)"07" == 7 converts the string to a number, so it's true, but === sees a string and an int. Casting first, then comparing with ===, is the clean way. "0" is falsy. "1e3" is a numeric string meaning 1000, so == compares them as numbers. And (int) "3.99 pesos" reads the leading number and cuts off the decimals.
Try it yourself
- Change
$ticketsto"0.0". What does the tickets line print now, and why? - What does
var_dump("abc" == "ABC");print? Try it and explain. - Write a line that turns
"19.75"into a float and adds0.25to it, with no warnings.
Check your understanding
Up next
You know how PHP decides what's true and false. Now put that to work, and let your code choose what to do, in Making Decisions: if, elseif, and else.
