<p>PHP中int和float类型运行时确定但赋值后固定,除法结果恒为float,整数溢出静默转float,浮点数存在精度误差,比较需用abs($a - $b) < epsilon。</p>

PHP整数和浮点数不是“自动切换”的类型
PHP 的 int 和 float 是运行时决定的,但一旦赋值,类型就固定了——除非你显式转换。很多人以为 10 / 3 会“自然”得到 float,其实它确实会(结果是 3.3333333333333),但 10 / 2 在 PHP 8+ 默认仍是 float,不是 int;而 10 + 2 这种纯整数运算才保持 int。
常见错误现象:var_dump(10 / 2) 输出 float(5),不是 int(5);有人据此做 is_int() 判断失败,却没意识到除法天生倾向 float。
- 整数溢出时 PHP 会静默转成
float(比如在 32 位系统上2147483647 + 1变成2147483648.0) -
float有精度限制,0.1 + 0.2 !== 0.3是真实发生的,不是“理论上”,而是直接var_dump(0.1 + 0.2)显示0.30000000000000004 - 用
==比较浮点数大概率出错,必须用abs($a - $b) 这类容差判断
什么时候该用 intval()、floatval() 或强制类型转换
类型转换不是为了“看起来像”,而是为了控制行为:比如数据库写入要求整型字段不能存 float,或 JSON 编码时 float 带小数点会让前端误判类型。
使用场景举例:接收 URL 参数 $_GET['id'],即使传的是 123,它也是 string;直接参与算术可能没问题,但进 PDO 绑定或 Redis key 就可能出问题。
立即学习“PHP免费学习笔记(深入)”;
-
intval($str)截断取整,intval("123.9") → 123,不四舍五入 -
(int)$str行为和intval()基本一致,但遇到空字符串或非数字开头时都返回0,而intval("", 10)也一样 -
floatval($str)或(float)$str对"123.45abc"会解析出123.45,但"abc123"得0.0 - 想严格校验并拒绝非法输入,别用转换函数,改用
filter_var($str, FILTER_VALIDATE_INT)或正则/^\d+$/
用 is_int() 和 is_float() 判断前先想清楚“为什么需要判断”
这两个函数检查的是变量当前的底层类型,不是“数学意义是否为整数”。比如 $x = 5.0,is_int($x) 返回 false,哪怕它数学上等于整数。
典型误用:收到一个 API 参数,想确认“是不是整数”,结果写了 if (is_int($_POST['limit'])) { ... } ——但 POST 数据永远是 string,这个判断永远 false。
- 对用户输入,先用
filter_var($input, FILTER_VALIDATE_INT)验证合法性,再用(int)转换 - 对计算结果,如
$result = $a / $b,若业务要求必须是整数(比如分页 offset),应明确floor()、ceil()或round(),而不是靠is_int()去“碰运气” -
gettype($x)可以看到真实类型,比is_*系列更透明,适合调试时快速确认
浮点数精度问题在钱、ID、时间戳里特别危险
用 float 存金额是最常见的翻车点。PHP 不会警告你,MySQL 如果字段是 DECIMAL,反而会帮你截断,但 PHP 层已经丢失精度了。
另一个隐蔽坑:用 microtime(true) 做唯一 ID 或排序依据,返回的是 float,在高并发下两个请求可能拿到完全相同的值(因为浮点精度不够表达微秒级差异)。
- 金额一律用整数单位(如“分”)存
int,运算用bcadd()、bcmul()等 BCMath 函数 - 需要高精度时间标识,改用
hrtime(true)(PHP 7.3+),返回纳秒级 int - 生成唯一 ID 不要拼接
microtime()+ rand(),改用sodium_crypto_random_bytes()或 UUID 库 - 如果必须用 float 做等值比较(比如缓存 key),先格式化为固定小数位字符串:
number_format($f, 6, '.', '')
类型不是语法装饰,是数据契约。PHP 宽松,但业务逻辑不会宽容一次隐式转换带来的精度偏移或类型错位。



















