该错误本质是用非法类型(如对象、数组、null等)作数组键,因PHP仅允许整数或字符串作下标;常见于isset/empty中传入对象或数组变量,或误将JSON字符串、未转义对象直接用于索引。

直接说结论:这个错误本质是“用不能当数组键的东西去当了数组键”,最常见的是把对象、数组、null 或资源类型变量,直接写在了方括号里,比如 $arr[$obj]、$arr[$data]、isset($arr[$user])。
为什么会出现 Illegal offset type
PHP 只允许整数(int)或字符串(string)作为数组下标。其他类型——比如对象实例、数组本身、null、资源(resource)、布尔值(true/false)——都不合法。
常见触发场景包括:
- 把一个未解码的 JSON 字符串当数组用:
$json = '{"id":1}'; $id = $json['id'];($json是字符串,不是数组) - 误把对象当数组键:
$user = new User(); $data[$user] = 'xxx'; - 把整个子数组当键名用:
$row = ['id'=>123, 'name'=>'a']; $list[$row]['status'] = 'done';($row是数组) - 在
isset()或empty()中传入非法键:isset($config[$settings]),而$settings是个对象
isset() 和 empty() 里最容易踩坑
这两个函数对键类型更敏感,尤其在 ThinkPHP 等框架中高频出现。错误往往藏在深层嵌套或动态拼接的键名里。
立即学习“PHP免费学习笔记(深入)”;
例如这段代码会报错:
$all = Config::get('ACTIVITY_LEVEL_LIST'); // 返回一维关联数组
foreach ($data as $d => $v) {
$data[$d]['level'] = isset($all[$v]) ? $all[$v] : '异常'; // ❌ $v 是数组,不能当 $all 的键
}
正确写法是明确提取键值:
- 确认你要查的是哪个字段,比如
$v['level_id'] - 加类型判断再访问:
isset($v['level_id']) && is_scalar($v['level_id']) && isset($all[$v['level_id']]) - 或者先过滤:
$key = $v['level_id'] ?? null; if (is_string($key) || is_int($key)) { ... }
怎么快速定位和修复
错误提示末尾的行号(如 on line 315)非常关键,但别只盯着那行——要顺着变量源头往上查。
- 用
var_dump(gettype($key), $key)打印出疑似键变量的类型和值,确认是不是对象/数组/null - 检查该变量是否来自
json_decode():默认返回对象,要加第二个参数true才得数组:json_decode($str, true) - 检查是否被意外覆盖:比如
$uid = []; $uid = $userModel->find(1);后又写了$list[$uid]['name'],此时$uid已是对象 - 在访问前强制转换不保险,比如
(string)$obj可能得"Object",仍不是有效键;优先改逻辑,而不是硬转类型
真正麻烦的不是语法错,而是那个“键”本意是 ID 或 code,结果上游传进来的是个完整对象或空数组,却没人校验。这类问题在接口联调、配置读取、缓存反序列化时特别隐蔽,建议所有外部输入的键变量,统一加 is_scalar() 判断。



















