Integers & Floats
PHP gives you two numeric scalar types for arithmetic: int for whole numbers and float (also called double) for numbers with a fractional part. Unlike languages such as C or Java, you never declare the width of an integer or choose between float and double — PHP picks a sensible platform-dependent size for you and silently converts between the two types as arithmetic demands it. That convenience is also where the surprises live: integers can overflow into floats without warning, and floats can never represent most decimal fractions exactly. Understanding both behaviors up front saves you from very confusing bugs later, especially around money and comparisons.
Integers: whole numbers with a platform-dependent ceiling
An int in PHP is a whole number, positive or negative, with no decimal point. Internally PHP typically uses the native word size of the machine it runs on — 64 bits on virtually every server and desktop today — which gives you a huge but still finite range. You can inspect the exact limits with the built-in constants PHP_INT_MAX, PHP_INT_MIN, and PHP_INT_SIZE.
Inspecting the integer range
<?php echo PHP_INT_MAX . PHP_EOL; // largest representable int echo PHP_INT_MIN . PHP_EOL; // smallest representable int echo PHP_INT_SIZE . PHP_EOL; // size in bytes (8 on a 64-bit build)
9223372036854775807 -9223372036854775808 8
Because that ceiling is tied to the platform, code that assumes a specific integer width (say, 32-bit wraparound behavior from another language) will behave differently on a 64-bit PHP build. If you ship code that must run identically everywhere, don't hardcode assumptions about PHP_INT_MAX — read the constant instead.
Integer overflow: PHP promotes to float instead of wrapping
Many languages let integers "wrap around" on overflow (a max value plus one silently becomes the minimum value). PHP does not do that. When an integer operation would exceed PHP_INT_MAX or go below PHP_INT_MIN, PHP automatically promotes the result to a float instead of throwing an error or wrapping. This keeps the number mathematically closer to correct, but it also means the result loses integer precision once it's large enough, because floats can't represent every large integer exactly either.
Overflow promotes silently to float
<?php $max = PHP_INT_MAX; var_dump($max); // int(9223372036854775807) var_dump($max + 1); // float(9.2233720368548E+18) echo gettype($max + 1) . PHP_EOL;
int(9223372036854775807) float(9.2233720368548E+18) double
Floats: fast, but not exact
A float stores numbers using the IEEE 754 double-precision format, the same representation used by nearly every mainstream language. That format is binary, which means it can represent binary fractions exactly (like 0.5 or 0.25) but cannot exactly represent most decimal fractions (like 0.1 or 0.2), for the same reason 1/3 has no exact finite decimal representation. The classic symptom:
The 0.1 + 0.2 surprise
<?php
$sum = 0.1 + 0.2;
var_dump($sum === 0.3); // bool(false)
printf("%.20f\n", $sum); // shows the tiny binary rounding error
echo $sum . PHP_EOL; // 0.3 (default precision hides it)bool(false) 0.30000000000000004441 0.3
PHP's default echo/print formatting rounds the displayed digits, which is why $sum looks like 0.3 even though the stored value is very slightly larger. The mismatch only becomes visible when you compare floats with === or ==, or when you print with enough decimal places using printf or number_format.
Safe float comparison
<?php
function floatsAreEqual(float $a, float $b, float $epsilon = 1e-9): bool
{
return abs($a - $b) < $epsilon;
}
var_dump(floatsAreEqual(0.1 + 0.2, 0.3)); // bool(true)bool(true)
Division: / always risks a float, intdiv() never does
PHP's / operator always performs floating-point-capable division — if the two operands divide evenly, you get an int-looking value that's actually still typed as whatever the division produced (an int when it divides evenly and both operands are int, a float otherwise). When you specifically want integer division — the quotient truncated toward zero, discarding the remainder — use intdiv() rather than casting the result of /.
/ vs intdiv()
<?php var_dump(10 / 4); // float(2.5) var_dump(10 / 5); // int(2) — divides evenly var_dump(intdiv(10, 4)); // int(2) — truncates toward zero var_dump(intdiv(-10, 4)); // int(-2) — truncates toward zero, not floor
float(2.5) int(2) int(2) int(-2)
Type juggling between int and float
Expression | Result type | Why |
|---|---|---|
|
| Both operands are int and the operator does not force a float |
|
| Does not divide evenly |
|
| Any float operand promotes the whole expression |
|
| Casting to int truncates, it does not round |
|
| Overflow promotion |
Casting truncates, it doesn't round
<?php var_dump((int) 5.9); // int(5) — not 6 var_dump((int) -5.9); // int(-5) — truncates toward zero var_dump((int) "42abc"); // int(42) — leading numeric prefix is parsed
int(5) int(-5) int(42)
intsize is platform-dependent; readPHP_INT_MAX/PHP_INT_SIZEinstead of hardcoding 32- or 64-bit assumptions.Integer overflow promotes to
floatsilently — no warning, no exception.Floats use binary IEEE 754 representation, so most decimal fractions are only approximated — never compare them with
==/===./can return eitherintorfloatdepending on whether it divides evenly;intdiv()always returnsintand truncates toward zero.Casting a float to
inttruncates the fractional part; it does not round.