尝试访问空值类型的数组偏移量

109

我在一个脚本(invoiceplane)中多次遇到这个错误,我已经使用了几年,但不幸的是该脚本没有得到其创作者的维护:

Message: Trying to access array offset on value of type null

我的服务器已经升级到 PHP 7.4,我正在寻找一种修复问题和自己维护脚本的方式,因为我对它非常满意。

这是导致错误的那一行:

$len = $cOTLdata['char_data'] === null ? 0 : count($cOTLdata['char_data']);

将$cOTLdata传递给函数:

public function trimOTLdata(&$cOTLdata, $Left = true, $Right = true)
{
    $len = $cOTLdata['char_data'] === null ? 0 : count($cOTLdata['char_data']);
    $nLeft = 0;
    $nRight = 0;
    //etc

顺便说一下,这已经包含在mpdf中,但简单地覆盖来自Github库的文件并不能解决错误。


更改为$len = count($cOTLdata['char_data'] ?? []); - Yevgeniy Afanasyev
我也遇到了同样的崩溃问题;我通过升级到mpdf8版本(我想是这个版本号)来解决了它。 - Owen Beresford
不幸的是,较新版本的PHP在这些声明方面更加严格。 - Andy McRae
3个回答

160
这是因为$cOTLdata为空。之前的PHP版本可能对这样的错误不太严格,并且在7.4中不再默默地吞噬错误/通知。
要检查$cOTLdata是否为空,请使用is_null()
is_null($cOTLdata)

这意味着该行应该看起来像这样:
$len = is_null($cOTLdata) ? 0 : count($cOTLdata['char_data']);

然而,如果既$cOTLdata$cOTLdata ['char_data']不存在,您可以同时使用isset()

$len = !isset($cOTLdata['char_data']) ? 0 : count($cOTLdata['char_data']);

3
我遇到了这个错误,但是我不理解你的解释。 - Kipruto
1
@kipruto 如果您没有找到满意的答案,您可以随时提出新问题。但请注意,即使这被标记为重复问题,因为这是一个相当常见的问题,所以阅读其他答案可能是一个很好的第一步。 - ArSeN
6
我强烈建议不要使用旧的PHP版本,比如7.2这样的版本,因为它已经不再受支持 - ArSeN
不,不总是。在进行转储时,我看到索引确实存在,但PHP 7.1仍然坚持它不存在。 - Debbie Kurth
3
我不认为这是正确的。如果索引不存在,你会得到“未定义的索引”(Undefined index)。这个错误意味着变量为空。 - Barmar
显示剩余7条评论

2

这个错误意味着你试图使用一个 null (或不存在的值)作为数组。这绝对意味着你程序逻辑有问题。

首先,你必须明白 PHP 生成的每一个错误信息都是为了帮助你,让你的代码更干净、更少出错。当你的代码出现 bug 时,最好的方法是修复它,而不是掩盖它。可惜,已被接受的答案只详细说明了后者。但你真的应该考虑前者。

每一个错误信息都能帮助你找到代码中的 bug。这意味着错误不应该是故意或“习惯性”的。这样你就不必将其屏蔽,而每个错误都意味着你的代码确实遇到了 bug。

就像你的情况一样。访问空或不存在的变量作为数组是没有意义的。 你只能在数组、特殊类型的对象上(仅使用数字索引)和字符串上使用数组偏移量。但是,如果你获得一个期望为数组的空值,则意味着程序中的数据流已经中断,你需要修复它。

就像你的情况一样。显然,$cOTLdata 包含 null,而你的代码期望它是一个数组。因此,你需要修复分配值给 $cOTLdata 的代码。

所以,作为一个规则,确保每个应该返回数组的函数都返回一个数组,或者任何应该包含数组的变量都包含一个数组。这样,你就不会再看到这个错误消息了。除非由于某些错误,你的代码意外地返回一个非数组值。而这个错误消息将帮助你定位这个问题。

当事情不在你的控制之下时,比如说,你需要从外部变量获取一个数组,首先要进行验证。例如,如果你期望从表单中获得一个必需的数组,请先验证它并返回错误,例如:

if (!$isset($_POST['options']) || !is_array($_POST['options'])) {
   // inform the user ad stop execution
} else {
    $options = $_POST['options'];
}
// now you can safely use count() on $options

如果数组是可选的,您可以将其初始化为空数组:

if (!$isset($_POST['options'])) {
    $options = [];
} elseif (!is_array($_POST['options'])
   // inform the user ad stop execution
} else {
    $options = $_POST['options'];
}
// now you can safely use count() on $options

只有在万不得已的情况下,您才可以使用is_null()isset()来消除此错误。

但是,您不应该盲目地将其用作通用解决方案。使用isset()无法解决问题。它只会把问题藏起来,实际上充当错误抑制运算符,因此当某些函数开始返回不正确的值时,您将永远不会收到有用的错误消息,解释为什么您的程序突然停止工作。


0
快速修复,适用于那些不需要深入细节的人,我很欣赏。我使用的是过时的XenForo设置说明。
if ($_POST['t'] == 0) {
    /* get by id */
    $finder = \XF::finder('XF:User');
    $user = $finder->where('user_id', $_POST['v'])->fetchOne();
} else {
    /* get by name */
    $finder = \XF::finder('XF:User');
    $user = $finder->where('username', $_POST['v'])->fetchOne();
}
$columns = array("user_id", "username", "last_username");
for ($i = 0; $i < sizeof($columns); $i++) {
    $column = $columns[$i];
    $columns[$i] = array($column, $user[$column]);
}

所以只需添加 php !isset || !is_array
if (!isset($_POST['t']) || !is_array($_POST['t'])) {
    /* get by id */
    $finder = \XF::finder('XF:User');
    $user = $finder->where('user_id', $_POST['v'])->fetchOne();
} else {
    /* get by name */
    $finder = \XF::finder('XF:User');
    $user = $finder->where('username', $_POST['v'])->fetchOne();
}
$columns = array("user_id", "username", "last_username");
for ($i = 0; $i < sizeof($columns); $i++) {
    $column = $columns[$i];
    $columns[$i] = array($column, $user[$column]);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接