“注意:未定义变量”,“注意:未定义索引”,“警告:未定义的数组键”和“注意:未定义偏移量”使用PHP

1357

我正在运行一个PHP脚本,但一直收到以下错误:

注意:在C:\wamp\www\mypath\index.php的第10行中未定义变量my_variable_name

注意:在C:\wamp\www\mypath\index.php的第11行中未定义索引my_index

警告:在C:\wamp\www\mypath\index.php的第11行中未定义数组键"my_index"

第10和11行如下所示:

echo "My variable value is: " . $my_variable_name;
echo "My index value is: " . $my_array["my_index"];

这些错误信息的意思是什么?
它们为什么突然出现?我用了这个脚本好多年,从来没有遇到过任何问题。
我该如何修复它们?
这是一个通用参考问题,供人们链接重复问题,而不必一遍又一遍地解释问题。我觉得这是必要的,因为大多数关于这个问题的现实答案都非常具体。
相关的Meta讨论:
- 如何解决重复问题? - “参考问题”有意义吗?

15
可能是 参考资料 - PHP 中这个错误是什么意思? 的重复问题。 - user229044
4
这个变量可能还没有被初始化。你是否正在从POST、GET或任何数组中初始化这个变量?如果是这种情况,你可能没有在访问的数组中拥有相应的字段。 - Anish Silwal
4
@Pekka웃 - 我注意到编辑中添加了“Notice: Undefined offset”这一内容 - 是否使用“PHP:“未定义变量”,“未定义索引”,“未定义偏移”通知”更合理呢?(可以省略PHP,因为它已被标记为“php”。此外,URL在“and-notice-undef”处被截断,建议调整以避免截断。甚至可以删除(过多的)引号,或者改为“PHP:未定义变量/索引/偏移通知”。 - Funk Forty Niner
4
@Fred,我认为两种变体都可以辩解。新手可能会将整个行,包括“注意:”部分输入他们的搜索查询中,我相信这是此问题的主要流量生成器。如果消息完整存在,那么在搜索引擎中的可见性可能会得到提高。 - Pekka
3
我明白了。我之前说那个是因为URL没有被切断,现在它被切断了,只到 and-notice-undef。这只是一些建议。它只是重复自己,并且是“注意:未定义”。 - Funk Forty Niner
显示剩余7条评论
29个回答

24

为什么会发生这种情况?

随着时间的推移,PHP已成为一个更加注重安全的语言。以前默认关闭的设置现在默认打开。一个完美的例子是E_STRICT,从PHP 5.4.0开始默认打开。

此外,根据PHP文档,默认情况下,在文件php.ini中禁用E_NOTICE。PHP文档建议为了调试目的将其打开。然而,当我从Ubuntu存储库和BitNami的Windows堆栈下载PHP时,我看到了其他东西。

; Common Values:
;   E_ALL (Show all errors, warnings and notices including coding standards.)
;   E_ALL & ~E_NOTICE  (Show all errors, except for notices)
;   E_ALL & ~E_NOTICE & ~E_STRICT  (Show all errors, except for notices and coding standards warnings.)
;   E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR  (Show only errors)
; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
; Development Value: E_ALL
; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
; http://php.net/error-reporting
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT

请注意,默认情况下,error_reporting实际上被设置为生产值,而不是默认值。这有些令人困惑,并且在php.ini之外没有记录,因此我尚未在其他发行版上进行验证。
然而,回答你的问题,现在出现这个错误是因为:
1. 安装了PHP并且新的默认设置文档化程度较低,但不排除E_NOTICE。 2. E_NOTICE警告(如未定义变量和索引)实际上有助于使您的代码更清晰、更安全。我可以告诉你,几年前,启用E_NOTICE强制我声明我的变量。这使得学习C语言变得容易得多。在C语言中,不声明变量会更加麻烦。

我该怎么做?

  1. 通过复制“默认值”E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED并将其替换为当前在error_reporting =等号后未被注释的内容,关闭E_NOTICE。重新启动Apache,或者如果使用CGI或FPM,则重新启动PHP。确保您正在编辑“正确”的php.ini文件。如果您正在使用Apache运行PHP,则正确的文件将是Apache,如果正在运行PHP-FPM,则是fpm或php-fpm,如果正在运行PHP-CGI,则是cgi等。这不是推荐的方法,但如果您有遗留代码,而且很难进行编辑,则可能是最好的选择。

  2. 在文件或文件夹级别上关闭E_NOTICE。如果您有一些遗留代码,但希望以其他方式做正确的事情,则可能更可取。要执行此操作,您应该咨询Apache 2、Nginx或您选择的任何服务器。在Apache中,您将在<Directory>内部使用php_value

  3. 重写您的代码使其更加清晰。如果您需要在移动到生产环境时或不希望有人看到您的错误时执行此操作,请确保禁用任何错误显示,并仅记录您的错误(请参见php.ini和服务器设置中的display_errorslog_errors)。

To expand on option 3: 这是理想情况。如果可以采用这种方式,应该采用。如果一开始没有使用这种方式,请考虑通过在开发环境中测试代码来最终采用此方式。顺便摆脱~E_STRICT~E_DEPRECATED,以查看将来可能出现的问题。你会看到很多不熟悉的错误,但当你需要升级PHP时,这将防止你遇到任何不愉快的问题。

这些错误是什么意思?

Undefined variable: my_variable_name - 当变量在使用前未定义时会出现此错误。当执行PHP脚本时,它内部只假设一个空值。然而,在哪种情况下需要在定义变量之前检查变量呢?最终,这是对“松散代码”的论据。作为一名开发人员,我可以告诉你,当我看到一个开源项目的变量被定义在其范围的最高位置时,我感到非常高兴。这使得更容易预测未来会出现哪些变量,并且更容易阅读/学习代码。

function foo()
{
    $my_variable_name = '';

    //....

    if ($my_variable_name) {
        // perform some logic
    }
}

未定义的索引:my_index - 当你尝试访问数组中不存在的值时,就会发生这种情况。为了防止出现这个错误,请进行条件检查。

// verbose way - generally better
if (isset($my_array['my_index'])) {
    echo "My index value is: " . $my_array['my_index'];
}

// non-verbose ternary example - I use this sometimes for small rules.
$my_index_val = isset($my_array['my_index'])?$my_array['my_index']:'(undefined)';
echo "My index value is: " . $my_index_val;

另一种选择是在函数顶部声明一个空数组。但这并非总是可行。

$my_array = array(
    'my_index' => ''
);

//...

$my_array['my_index'] = 'new string';

(附加提示)

  • 当我遇到这些和其他问题时,我使用免费的 NetBeanss IDE,它给了我一堆警告和通知。其中一些提供非常有用的提示。这不是必需的,除了大型项目外,我不再使用IDE。现在我更喜欢vim

20

在PHP 7.0中,现在可以使用null合并运算符

echo "My index value is: " . ($my_array["my_index"] ?? '');

等于:

echo "My index value is: " . (isset($my_array["my_index"]) ? $my_array["my_index"] : '');

PHP 手册 PHP 7.0


这在if语句中也可以正常工作。if (is_array($my_array['idontexist'] ?? '')) { dosomething(); } - a coder
你的代码实际上是一个被忽视的漏洞: ?? - 只检查 isset(),如果你传递了一个布尔值的 is_array(),将会出现意外行为。 - elpiel

20

我曾经咒骂这个错误,但它可以帮助您提醒要转义用户输入。

例如,如果你认为这是聪明的简写代码:

// Echo whatever the hell this is
<?=$_POST['something']?>

...再想一想!更好的解决方案是:

// If this is set, echo a filtered version
<?=isset($_POST['something']) ? html($_POST['something']) : ''?>

(我使用自定义的html()函数来转义字符,您的结果可能会有所不同)


17

我一直使用自己的有用函数exst(),它可以自动声明变量。

你的代码将会是 -

$greeting = "Hello, " . exst($user_name, 'Visitor') . " from " . exst($user_location);


/**
 * Function exst() - Checks if the variable has been set
 * (copy/paste it in any place of your code)
 *
 * If the variable is set and not empty returns the variable (no transformation)
 * If the variable is not set or empty, returns the $default value
 *
 * @param  mixed $var
 * @param  mixed $default
 *
 * @return mixed
 */

function exst(& $var, $default = "")
{
    $t = "";
    if (!isset($var) || !$var) {
        if (isset($default) && $default != "")
            $t = $default;
    }
    else  {
        $t = $var;
    }
    if (is_string($t))
        $t = trim($t);
    return $t;
}

15

用非常简单的语言来说:

你犯了一个错误,你使用了一个变量$user_location,但是你之前没有定义过它,也没有给它任何值。因此,我建议在使用它之前,请先声明这个变量。例如:


$ user_location ='';
或者
$ user_location ='洛杉矶';

这是一个非常常见的错误,所以不要担心;只需声明变量,就可以愉快地编码


11

保持简单:

<?php
    error_reporting(E_ALL); // Making sure all notices are on

    function idxVal(&$var, $default = null) {
        return empty($var) ? $var = $default : $var;
    }

    echo idxVal($arr['test']);         // Returns null without any notice
    echo idxVal($arr['hey ho'], 'yo'); // Returns yo and assigns it to the array index. Nice
?>

9

未定义的索引在数组中表示您请求了一个不可用的数组索引。例如,

<?php
    $newArray[] = {1, 2, 3, 4, 5};
    print_r($newArray[5]);
?>

未定义变量意味着您使用了完全不存在的变量,或者该名称未被定义或初始化。例如:

<?php print_r($myvar); ?>

未定义的偏移量意味着你在数组中请求了一个不存在的键。解决方法是在使用之前进行检查:

php> echo array_key_exists(1, $myarray);

"php>"信号代表什么?是某种REPL吗?如果是,那是哪一种? - Peter Mortensen

7

关于问题的这一部分:

它们为什么会突然出现?我用这个脚本已经很多年了,从来没有遇到过任何问题。

没有明确的答案,但以下是一些可能的解释,解释为什么设置可能会“突然”更改:

  1. 您已将PHP升级到新版本,该版本可能具有其他默认值的error_reporting、display_errors或其他相关设置。

  2. 您已删除或引入了一些代码(可能在依赖项中),它们使用ini_set()或error_reporting()在运行时设置相关设置(在代码中搜索这些)

  3. 您更改了Web服务器配置(这里假设为Apache):.htaccess文件和vhost配置也可以操纵php设置。

  4. 通常不会显示/报告注意事项(请参见PHP手册),因此在设置服务器时可能无法加载php.ini文件(文件权限??),并且您处于默认设置。后来,“bug”已被解决(意外地),现在它可以加载正确的php.ini文件,其中error_reporting设置为显示通知。


7

使用三元运算符简单、易读、干净:

PHP 7之前

如果变量已设置,则将一个变量的值分配给另一个变量,否则分配null(或您需要的任何默认值):

$newVariable = isset($thePotentialData) ? $thePotentialData : null;

PHP 7+

使用null coalescing operator相同。现在不再需要调用isset(),因为它已经内置了,并且不需要提供要返回的变量,因为它被假定为返回正在检查的变量的值:

$newVariable = $thePotentialData ?? null;

两者都会停止原帖问题中的通知,并且两者是以下内容的确切等价:

if (isset($thePotentialData)) {
    $newVariable = $thePotentialData;
} else {
    $newVariable = null;
}

如果您不需要设置新变量,那么可以直接使用三元运算符的返回值,例如使用 echo、函数参数等:

输出:

echo 'Your name is: ' . isset($name) ? $name : 'You did not provide one';

功能:

$foreName = getForeName(isset($userId) ? $userId : null);

function getForeName($userId)
{
    if ($userId === null) {
        // Etc
    }
}

上述代码对于数组同样适用,包括会话等,将要检查的变量替换为例如:

$_SESSION['checkMe']

或者你需要多少层深度,例如:

$clients['personal']['address']['postcode']


抑制:

可以使用@来抑制PHP通知或降低错误报告级别,但这并不能解决问题。它只是停止将其报告到错误日志中。这意味着您的代码仍然尝试使用未设置的变量,这可能意味着某些内容无法按预期工作-具体取决于缺失值的重要性。

您应该真正检查此问题并适当地处理它,可以提供不同的消息,甚至只返回null值以识别精确状态。

如果只关心通知不在错误日志中,则可以选择忽略错误日志。


5

如果您正在使用类,需要确保使用$this引用成员变量:

class Person
{
    protected $firstName;
    protected $lastName;

    public function setFullName($first, $last)
    {
        // Correct
        $this->firstName = $first;

        // Incorrect
        $lastName = $last;

        // Incorrect
        $this->$lastName = $last;
    }
}

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