题 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"];

这些错误意味着什么?

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

我需要做些什么才能修复它们?

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

相关元讨论:


952


起源


可能重复 参考 - 这个错误在PHP中意味着什么? - meagar♦
变量可能尚未初始化。您是从帖子或获取或任何数组初始化变量?如果是这种情况,您可能在该数组中没有字段。你的访问。 - ASK
@Pekka웃 - 我注意到编辑添加了“和”注意:未定义的偏移“” - 使用“PHP:”未定义的变量“,”未定义的索引“,”未定义的偏移“通知”(甚至采取超出PHP,因为它被标记为“php”。另外,URL被切断了 and-notice-undef,只是一个建议,以便URL不会被切断。甚至可能删除(太多)引号。要么 PHP: “Undefined variable/index/offset” notices - Funk Forty Niner
@Fred我想可以为两种变化做出争论。新手有可能进入整个系列,包括“通知:”到他们的搜索查询中,我确信这是这个问题的主要流量生成器。如果消息完整存在,则可能会提高搜索引擎的可见性 - Pekka 웃
@Pekka웃我明白了。我只是说,因为URL之前没有被切断,现在它已经被切断了 and-notice-undef。这只是一个(少数)建议。它只是重复自己 Notice: Undefined。 - Funk Forty Niner


答案:


注意:未定义的变量

来自广大的智慧 PHP手册

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

PHP文档

如果变量不存在,则不会生成警告。这意味着       空() 本质上简洁等同于 !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,默认情况下甚至没有报告,但手册 建议允许 在开发期间。

处理问题的方法:

  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 operator

    // 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');
    

两个变量用于访问两个数组元素,但只有一个数组元素index 0,这将产生:

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

$_POST / $_GET / $_SESSION 变量

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

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

有关:


874



@ dieselpower44有几点想法:“关闭运营商”(@)有一些性能问题。此外,因为它抑制 所有 特定范围内的错误,无需小心使用它可能会掩盖您希望看到的消息。 - IMSoP
隐藏问题不是处理问题的方法。项目#2 ...#4只能在生产服务器上使用,一般情况下不能使用。 - Salman A
是否可以在使用自定义错误处理程序时内联消息(而不是在处理程序中)? $var = @$_GET['nonexisting']; 仍然引起通知.. - Alph.Dev
为什么建议使用1。 $value = isset($_POST['value']) ? $_POST['value'] : ''; 而不是使用4。 $value = @$_POST['value'];? - forsvunnet
@twistedpixel这四种方式是独立的,这不是一个4步指南。因此,如果您选择使用方式4,这意味着您没有实现前3种方式,所以您还没有遇到任何错误。 - Aycan Yaşıt


试试这些

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);

关于会话的说明:


110



如果使用 E_NOTICE 来自 php.ini 配置文件,做 error_reporting = (E_ALL & ~E_NOTICE) - ahmd0
这个答案正在讨论meta。 - Script47


一个(通常是气馁的)替代方案是 错误抑制操作符  @。它是一种特定的语言结构,用于关闭不需要的通知和警告,但应谨慎使用。

首先,它会因使用而导致微观性能下降 isset。这在现实世界的应用程序中是不可测量的,但应该在数据繁重的迭代中考虑。其次它可能阻碍调试,但同时抑制错误实际上传递给自定义错误处理程序(与isset修饰表达式不同)。


47



如果您很好奇性能影响是什么,本文总结了它, derickrethans.nl/...。 - Gajus
@ GajusKuizinas自2009年以来,特别是有一些变化 php.net/ChangeLog-5.php#5.4.0 彻底改变结果(参见“Zend Engine,performance”和“(silence)operator”)。 - mario
谢谢@mario,很有意思。现在,如果有人能够对这两个人进行基准评估...... 3v4l.org/CYVOn/perf#tabs  3v4l.org/FLp3D/perf#tabs 根据这个测试,似乎是相同的(注意规模变化)。 - Gajus
我用PHP 5.4进行了测试,性能仍然很差。 - Brynner Ferreira


这意味着您正在测试,评估或打印尚未分配任何内容的变量。这意味着您要么输入错误,要么需要先检查变量是否已初始化为某些内容。检查您的逻辑路径,它可以设置在一个路径中,但不能设置在另一个路径中。


36





一般是因为“糟糕的编程”,现在或以后都有可能出错。

  1. 如果这是一个错误,请首先对变量进行适当的赋值:$ varname = 0;
  2. 如果它确实只是有时定义,请测试它: if (isset($varname)),在使用之前
  3. 如果是因为你拼错了,那就纠正吧
  4. 甚至可能会在你身上发出警告 PHP的设置

34



请不要关闭警告。在更严格的语言中,它们通常意味着“可能存在一个错误,你最好两次检查这一行” - 在一种像PHP那样宽松的语言中,它们通常意味着“这段代码是废话并且充满了错误;我会尝试制作一些意义,但你最好尽快解决这个问题“。
虽然我同意前三点,但#4完全错了。隐藏问题不会让它消失,甚至可能导致更多问题。 - Valentin Flachsel
@Freek绝对正确,但在某些情况下(买了脚本,零技术知识,需要它明天运行......)这是管道胶带解决方案 - 非常糟糕,总是需要强调,但一个选项 - Pekka 웃
管道胶带很好......有时候。历史上警告已经在标准PHP设置中被转换,但是defult设置变得更加严格。太糟糕了许多人回到旧设置,以免惹恼客户。 - Erik


我不想禁用通知,因为它有用,但是想避免太多打字。

我的解决方案是这个功能:

function ifexists($varname)
{
  return(isset($$varname)?$varname:null);
}

所以,如果我想引用$ name和echo if exists,我只需写:

<?=ifexists('name')?>

对于数组元素:

function ifexistsidx($var,$index)
{
  return(isset($var[$index])?$var[$index]:null);
}

在页面中,如果我想引用$ _REQUEST ['name']:

<?=ifexistsidx($_REQUEST,'name')?>

31



您的ifexists()函数在PHP 5.3中对我不起作用。调用者的变量在函数的本地范围内不可用(参见 可变范围),除非他们是 超级全局 或者你搞砸了 $ GLOBALS所以 $foo = "BABAR"; ifexists('foo'); 通常会返回null。 (斜体是php.net章节。) - skierpage
现在你会得到“你好”......有什么意义?只需检查价值 if( !empty($user) and !empty($location) ) echo "hello $user ..." - gcb


获取输入的最佳方式  是:

$value = filter_input(INPUT_POST, 'value');

这个单线几乎相当于:

if (!isset($_POST['value'])) {
    $value = null;
} elseif (is_array($_POST['value'])) {
    $value = false;
} else {
    $value = $_POST['value'];
}

如果你绝对想要  价值,就像:

$value = (string)filter_input(INPUT_POST, 'value');

25