应使用 is_int($key) 或 is_string($key) 直接判断 foreach 遍历时获取的键类型;注意 JSON、$_GET 等来源的键恒为字符串,filter_var($key, FILTER_VALIDATE_INT) 可校验字符串是否实质等价于整数。
is_int() 和 is_string() 判断数组下标类型PHP 数组的下标可以是整数或字符串,但 isset()、array_key_exists() 这类函数不区分类型,只看“是否存在”。真要识别下标类型,得对键本身做类型判断。
常见错误是直接 var_dump($arr) 看输出,误以为 0 和 "0" 是一样的键 —— 实际上它们在数组里共存且互不影响:
$arr = [0 => 'a', "0" => 'b']; var_dump($arr); // 输出两个元素:int(0) => 'a', string(1) => 'b'
foreach ($arr as $key => $val) 拿到的 $key 就是原始类型,可直接用 is_int($key) 或 is_string($key) 判断is_numeric("0") 返回 true,但它不是 is_int();别用 is_numeric() 替代类型判断123、-5、0x1F(十六进制字面量)都算 is_int();而 "123"、"-5"、"0.0" 都是字符串array_keys() 返回的键可能全是字符串?当你从 JSON 解析、表单提交或某些数据库驱动(如 PDO 默认 fetch mode)拿到数组时,下标常被强制转为字符串 —— 即使原始数据是数字。这不是 bug,是 PHP 类型隐式转换的结果。
json_decode('{"0":"a","1":"b"}', true) 返回的数组,键是 "0"、"1" 字符串,不是整数$_GET、$_POST 所有键名永远是字符串,哪怕 URL 是 ?0=value
array_keys($arr, null, true) 不起作用 —— 第三个参数是搜索值是否严格匹配,和键类型无关filter_var() 辅助识别“可安全转为整数”的字符串下标有些场景你需要知道某个字符串键是否“实质等价于整数”,比如做索引校验或路由分发。这时 is_int() 太严格,is_numeric() 又太宽泛。
is_string($key) && filter_var($key, FILTER_VALIDATE_INT) !== false
"12.3"、"0x10"、" 42 "(带空格)、"+42"(默认不认正号),但接受 "-42"、"0"
FILTER_FLAG_ALLOW_OCTAL / FILTER_FLAG_ALLOW_HEX,但多数业务不需要ctype_digit(ltrim($key, '-')) 稍慢,但语义清晰、边界处理可靠gettype() 查键类型时容易忽略的细节gettype() 能返回 "integer" 或 "string",看起来万能,但实际有坑。
gettype(null) 返回 "null",但数组键不可能是 null,所以这个情况可忽略
[3.14 => 'x'] 等价于 [3 => 'x'],而 ["3.14" => 'y'] 保留为字符串键。你永远拿不到 gettype($key) === "double" 的数组键integer 和 string 两种;其他类型(如 bool)作键也会被强转:[true => 'a'] → 键变成 1(整数)array_merge、json_encode)可能悄悄改变它。动手前先确认数据来源,比写一堆 is_* 更省事。