协慌网

登录 贡献 社区

使用 PHP“注意:未定义的变量”,“注意:未定义的索引” 和 “通知:未定义的偏移量”

我正在运行 PHP 脚本,并继续收到如下错误:

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

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

第 10 行和第 11 行看起来像这样:

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

这些错误消息的含义是什么?

他们为什么突然出现?我曾经使用这个脚本多年,我从来没有遇到任何问题。

我该如何解决?

这是一个一般参考问题,供人们链接到重复,而不是一遍又一遍地解释这个问题。我觉得这是必要的,因为关于这个问题的大多数现实世界的答案都非常具体。

相关元讨论:

答案

注意:未定义的变量

来自PHP 手册的广博智慧:

在将一个文件包含到使用相同变量名称的另一个文件的情况下,依赖于未初始化变量的默认值是有问题的。打开register_globals也是一个主要的安全风险 。如果使用未初始化的变量,则会发出E_NOTICE级别错误,但是在未初始化的数组中附加元素时则不会。 isset()语言构造可用于检测变量是否已经初始化。另外,更理想的是empty()的解决方案,因为如果未初始化变量,它不会生成警告或错误消息。

PHP 文档

如果变量不存在,则不会生成警告。这意味着empty()基本上是!isset($ var)||的简洁等价物$ var == false

这意味着您只能使用empty()来确定是否设置了变量,此外它还会根据以下内容检查变量, 0,"",null

例:

$o = [];
@$var = ["",0,null,1,2,3,$foo,$o['myIndex']];
array_walk($var, function($v) {
    echo (!isset($v) || $v == false) ? 'true ' : 'false';
    echo ' ' . (empty($v) ? 'true' : 'false');
    echo "\n";
});

3v4l.org 在线 PHP 编辑器中测试上面的代码片段

尽管 PHP 不需要变量声明,但它确实建议使用它以避免一些安全漏洞或错误,因为人们会忘记为稍后将在脚本中使用的变量赋值。 PHP 在未声明变量的情况下所做的是发出一个非常低级别的错误E_NOTICE ,默认情况下甚至没有报告,但是 Manual 建议在开发期间允许

处理问题的方法:

  1. 建议:声明变量,例如,当您尝试将字符串附加到未定义的变量时。或者使用isset() / !empty()来检查它们是否在引用它们之前被声明,如:

    //Initializing variable
    $value = ""; //Initialization value; Examples
                 //"" When you want to append stuff later
                 //0  When you want to add numbers later
    //isset()
    $value = isset($_POST['value']) ? $_POST['value'] : '';
    //empty()
    $value = !empty($_POST['value']) ? $_POST['value'] : '';

    从 PHP 7.0 开始,这已变得更加清晰,现在您可以使用null coalesce 运算符

    // Null coalesce operator - No need to explicitly initialize the variable.
    $value = $_POST['value'] ?? '';
  2. 为 E_NOTICE 设置自定义错误处理程序 ,并将消息从标准输出重定向(可能是日志文件):

    set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
  3. 禁用报告中的 E_NOTICE。仅排除E_NOTICE快速方法是:

    error_reporting( error_reporting() & ~E_NOTICE )
  4. 使用@运算符抑制错误。

注意:强烈建议仅实施第 1 点。

注意:未定义的索引 / 未定义的偏移量

当您(或 PHP)尝试访问数组的未定义索引时,会出现此通知。

处理问题的方法:

  1. 在访问索引之前检查索引是否存在。为此,您可以使用isset()array_key_exists()

    //isset()
    $value = isset($array['my_index']) ? $array['my_index'] : '';
    //array_key_exists()
    $value = array_key_exists('my_index', $array) ? $array['my_index'] : '';
  2. 语言构造list()在尝试访问不存在的数组索引时可能会生成它:

    list($a, $b) = array(0 => 'a');
    //or
    list($one, $two) = explode(',', 'test string');

两个变量用于访问两个数组元素,但是只有一个数组元素,索引0 ,所以这将生成:

注意:未定义的偏移量:1

$_POST / $_GET / $_SESSION变量

使用$_POST$_GET$_SESSION时,通常会出现上述注意事项。对于$_POST$_GET您只需在使用之前检查索引是否存在。对于$_SESSION您必须确保以session_start()开始会话并且索引也存在。

另请注意,所有 3 个变量都是超全局变量并且是大写的。

有关:

试试这些

Q1:此通知表示 $ varname 未在脚本的当前范围内定义。

Q2:在使用任何可疑变量之前使用 isset(),empty()条件效果很好。

// recommended solution for recent PHP versions
$user_name = $_SESSION['user_name'] ?? '';

// pre-7 PHP versions
$user_name = '';
if (!empty($_SESSION['user_name'])) {
     $user_name = $_SESSION['user_name'];
}

或者,作为快速而肮脏的解决方案:

// not the best solution, but works
// in your php setting use, it helps hiding site wide notices
error_reporting(E_ALL ^ E_NOTICE);

关于会话的说明:

错误显示@运算符

对于不需要的和冗余的通知,可以使用专用的@运算符隐藏未定义的变量 / 索引消息。

$var = @($_GET["optional_param"]);
  • This is usually discouraged. Newcomers tend to way overuse it.
  • It's very inappropriate for code deep within the application logic (ignoring undeclared variables where you shouldn't), e.g. for function parameters, or in loops.
  • There's one upside over the isset?: or ?? super-supression however. Notices still can get logged. And one may resurrect @-hidden notices with: set_error_handler("var_dump");
    • Additonally you shouldn't habitually use/recommend if (isset($_POST["shubmit"])) in your initial code.
    • Newcomers won't spot such typos. It just deprives you of PHPs Notices for those very cases. Add @ or isset only after verifying functionality.
    • Fix the cause first. Not the notices.

  • @ is mainly acceptable for $_GET/$_POST input parameters, specifically if they're optional.

And since this covers the majority of such questions, let's expand on the most common causes:

$_GET / $_POST / $_REQUEST undefined input

  • First thing you do when encountering an undefined index/offset, is check for typos:
    $count = $_GET["whatnow?"];

    • Is this an expected key name and present on each page request?
    • Variable names and array indicies are case-sensitive in PHP.
  • Secondly, if the notice doesn't have an obvious cause, use var_dump or print_r to verify all input arrays for their curent content:

    var_dump($_GET);
    var_dump($_POST);
    //print_r($_REQUEST);

    Both will reveal if your script was invoked with the right or any parameters at all.

  • Alternativey or additionally use your browser devtools (F12) and inspect the network tab for requests and parameters:

    browser developer tools / network tab

    POST parameters and GET input will be be shown separately.

  • For $_GET parameters you can also peek at the QUERY_STRING in

    print_r($_SERVER);

    PHP has some rules to coalesce non-standard parameter names into the superglobals. Apache might do some rewriting as well. You can also look at supplied raw $_COOKIES and other HTTP request headers that way.

  • More obviously look at your browser address bar for GET parameters:

    http://example.org/script.php?id=5&sort=desc

    The name=value pairs after the ? question mark are your query (GET) parameters. Thus this URL could only possibly yield $_GET["id"] and $_GET["sort"].

  • Finally check your <form> and <input> declarations, if you expect a parameter but receive none.

    • Ensure each required input has an <input name=FOO>
    • The id= or title= attribute does not suffice.
    • A method=POST form ought to populate $_POST.
    • Whereas a method=GET (or leaving it out) would yield $_GET variables.
    • It's also possible for a form to supply action=script.php?get=param via $_GET and the remaining method=POST fields in $_POST alongside.
    • With modern PHP configurations (≥ 5.6) it has become feasible (not fashionable) to use $_REQUEST['vars'] again, which mashes GET and POST params.
  • If you are employing mod_rewrite, then you should check both the access.log as well as enable the RewriteLog to figure out absent parameters.

$_FILES

  • The same sanity checks apply to file uploads and $_FILES["formname"].
  • Moreover check for enctype=multipart/form-data
  • As well as method=POST in your <form> declaration.
  • See also: PHP Undefined index error $_FILES?

$_COOKIE

  • The $_COOKIE array is never populated right after setcookie(), but only on any followup HTTP request.
  • Additionally their validity times out, they could be constraint to subdomains or individual paths, and user and browser can just reject or delete them.