intval() 仅返回整数值而不改变原变量类型,需用 $x = intval($x) 或 (int)$x 赋值覆盖;处理用户输入时应先过滤再转换并校验范围,大数字须用 filter_var 防溢出。

intval() 不是类型强制,只是取整转换
很多人以为 intval() 能把变量“变成 int 类型”,其实它只是返回一个整数值,原变量类型完全不变。比如 $x = "123abc",调用 intval($x) 得到 123,但 $x 本身还是 string —— 这点在函数传参、类型检查、JSON 序列化时特别容易翻车。
常见错误现象:is_int($x) 依然返回 false;json_encode(['id' => $x]) 输出字符串 "123abc" 而不是数字 123;用在数据库查询绑定参数时,PDO 可能仍按 string 处理。
- 真正需要“保证是整型变量”,得用赋值覆盖:
$x = intval($x); - 注意进制问题:默认十进制,
intval("0xFF", 0)才会自动识别十六进制,不写第二个参数就是纯按十进制截断 -
intval(null)返回0,intval([])也返回0,不是报错——这和类型断言预期不符
想真正强制 int 类型,该用 (int) 还是 settype()?
(int) 和 settype($x, 'integer') 都会修改变量类型,但行为有关键差异:前者返回新值(不影响原变量,除非显式赋值),后者直接改原变量并返回 true/false。
使用场景:如果只是临时需要整数参与计算,(int)$x 更轻量;如果后续所有逻辑都依赖 $x 是 int(比如作为数组 key 或严格比较),必须用 settype($x, 'integer') 或 $x = (int)$x。
立即学习“PHP免费学习笔记(深入)”;
-
(int)"12.9"→12(截断,非四舍五入) -
(int)"12abc"→12(从头读到第一个非数字字符为止) -
(int)[]→0,(int)false→0,(int)true→1 -
settype($x, 'integer')对对象、资源等无效,返回false,且$x不变
PHP 8+ 类型声明不能替代运行时转换
哪怕你写了 function foo(int $x): int,调用 foo("123") 在启用了严格模式(declare(strict_types=1))时会报 TypeError,但错误发生在函数入口,不是自动帮你转类型。很多开发者误以为加了类型提示就“安全”了,结果漏掉上游数据(如 $_GET、JSON 解析结果)仍是 string。
性能影响:类型声明本身无 runtime 开销,但错误抛出和捕获成本远高于提前转换。尤其高频接口中,宁可 $id = (int)$_GET['id'],别赌用户传的是数字字符串。
- $_GET/$_POST 值永远是 string,无论浏览器传的是
123还是123.0 - json_decode() 默认返回 assoc array,数字键仍是 string,需手动遍历转换
- MySQLi/PDO 查询结果中的数字字段,取决于驱动配置(
MYSQLI_OPT_INT_AND_FLOAT_NATIVE等),不设的话全是 string
最稳妥的“强制整型”组合写法
没有万能银弹,但针对不同来源,可以分层处理:先过滤非法字符(防注入/异常),再转类型,最后校验范围。比如处理用户 ID:
$raw = $_GET['id'] ?? '';
// 先粗筛:只留数字和负号,避免 intval(" -123 ") 返回 0
$clean = preg_replace('/[^-0-9]/', '', $raw);
// 再转类型,空字符串变 0,但至少可控
$id = (int)$clean;
// 最后业务校验(比如 ID 不能为 0 或负数)
if ($id < 1 || $id > PHP_INT_MAX) {
throw new InvalidArgumentException('Invalid ID');
}
容易被忽略的一点:intval("999999999999999999999") 在 64 位系统上会溢出成 PHP_INT_MAX,而 (int) 同样截断——大数字字符串必须用 filter_var($s, FILTER_VALIDATE_INT) 配合 options 检查范围,否则静默出错。











