PHP8下出现未初始化字符串偏移及类型错误的技术求助
PHP 8升级后字符串偏移与类型错误排查解决
错误信息
- 警告错误:
Warning: Uninitialized string offset 0 in
错误触发代码行:if($subMenues[$j]['id'] == $permisosMod[$k]['id_sub_menus']){
- 致命错误:
Fatal error: Uncaught TypeError: Cannot access offset of type string on string in C:\xampp\htdocs\ebsoftap\Controllers\Setupdashboard.php:29 Stack trace: #0 C:\xampp\htdocs\ebsoftap\Libraries\Core\Load.php(12): Setupdashboard->Setupdashboard('') #1 C:\xampp\htdocs\ebsoftap\Index.php(33): require_once('C:\xampp\htdocs...') #2
问题代码
public function Setupdashboard(){ $data['page_tag'] = "Configuración - Empresa*"; $data['page_title'] = "Configuración - Empresa*"; $data['page_name'] = "setupdashboard"; $data['permisos'] = $_SESSION['permisos']; $data['permisosMod'] = $_SESSION['permisosMod']; $data['ThisModulo'] = getModulo(get_class($this)); $_SESSION['moduloFull'] = $this->model->selectModulo($data['ThisModulo']); $data['menues'] = $this->model->selectMenues($data['ThisModulo']); for ($i=0; $i < count($data['menues']); $i++) { $subMenues = $data['menues'][$i]['subMenues']; for ($j=0; $j < count((array)$subMenues); $j++) { $permisosMod = $data['permisosMod']; for ($k=0; $k < count($permisosMod); $k++) { if($subMenues[$j]['id'] == $permisosMod[$k]['id_sub_menus']){ $data['menues'][$i]['subMenues'][$j]['r'] = $permisosMod[$k]['r']; $data['menues'][$i]['subMenues'][$j]['w'] = $permisosMod[$k]['w']; $data['menues'][$i]['subMenues'][$j]['u'] = $permisosMod[$k]['u']; $data['menues'][$i]['subMenues'][$j]['d'] = $permisosMod[$k]['d']; } } } } $data['nav_bar'] = "nav_admin.php"; $data['page_functions_js'] = "functions_dsetupsdashboard.js"; $this->views->getView($this,"setupdashboard",$data); }
问题根源
PHP 8对类型检查的严格性大幅提升:
- 旧版本PHP中,当
$subMenues是字符串(比如空字符串)时,强制转成数组(array)$subMenues会把字符串转为索引数组(例如"test"转为[0 => "test"]),循环访问超出字符串长度的索引只会抛出警告;但PHP 8直接抛出致命TypeError,禁止对字符串使用数组偏移访问。 - 代码中未对
$subMenues、$permisosMod的类型做校验,当数据源返回非数组值时,就会触发错误。
排查与解决方法
1. 前置校验数据类型
在处理子菜单和权限数据前,先确保它们是数组类型,避免非数组值进入循环:
for ($i=0; $i < count($data['menues']); $i++) { $subMenues = $data['menues'][$i]['subMenues']; // 校验并修正subMenues类型 if (!is_array($subMenues)) { $subMenues = []; $data['menues'][$i]['subMenues'] = $subMenues; } for ($j=0; $j < count($subMenues); $j++) { $permisosMod = $data['permisosMod']; // 校验并修正permisosMod类型 if (!is_array($permisosMod)) { $permisosMod = []; } for ($k=0; $k < count($permisosMod); $k++) { // ... 后续代码 } } }
2. 增加索引存在性检查
在访问数组偏移前,先确认索引存在,避免未初始化偏移警告:
if (isset($subMenues[$j]['id'], $permisosMod[$k]['id_sub_menus']) && $subMenues[$j]['id'] == $permisosMod[$k]['id_sub_menus']) { $data['menues'][$i]['subMenues'][$j]['r'] = $permisosMod[$k]['r']; $data['menues'][$i]['subMenues'][$j]['w'] = $permisosMod[$k]['w']; $data['menues'][$i]['subMenues'][$j]['u'] = $permisosMod[$k]['u']; $data['menues'][$i]['subMenues'][$j]['d'] = $permisosMod[$k]['d']; }
3. 修正数据源(Model层)
排查selectMenues方法,确保返回的subMenues字段始终为数组类型——当没有子菜单时,返回空数组[]而非空字符串或其他非数组值,从根源解决数据类型不一致问题。
内容的提问来源于stack exchange,提问作者Jonathan Luna
相关产品推荐
相关产品推荐

