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

注意:未定义变量my_variable_name在C:\wamp\www\mypath\index.php第10行 注意:第11行未定义索引:my_index C:\wamp\www\mypath\index.php 警告:在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"];

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

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

我该如何修复它们?


这是一个一般参考问题,供人们链接作为副本,而不是需要一遍又一遍地解释这个问题。我觉得这很有必要,因为现实世界中关于这个问题的答案都非常具体。 相关元讨论: 如何应对重复的问题? “参考问题”有意义吗?


当前回答

未定义的索引意味着在您请求的数组中,数组索引不可用。例如,

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

一个未定义的变量意味着你完全没有使用一个现有的变量,或者这个变量没有定义或初始化。例如,

<?php print_r($myvar); ?>

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

php> echo array_key_exists(1, $myarray);

其他回答

我曾经诅咒过这个错误,但是提醒您转义用户输入是有帮助的。

例如,如果你认为这是聪明的,速记代码:

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

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

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

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

为什么会这样?

随着时间的推移,PHP已经成为一种更加关注安全的语言。以前默认关闭的设置现在默认打开了。E_STRICT就是一个很好的例子,它在PHP 5.4.0时默认开启。

此外,根据PHP文档,默认情况下,E_NOTICE在PHP .ini文件中是禁用的。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实际上默认设置为生产值,而不是默认设置为“default”值。这有点令人困惑,并且在php.ini之外没有记录,所以我没有在其他发行版上验证这一点。

为了回答你的问题,然而,这个错误现在弹出时,它没有弹出之前,因为:

您安装了PHP,新的默认设置的文档很少,但不排除E_NOTICE。 E_NOTICE警告,如未定义变量和未定义索引,实际上有助于使您的代码更干净和更安全。我可以告诉你,几年前,保持E_NOTICE启用迫使我声明我的变量。在C语言中,不声明变量是一个更大的麻烦。

我能做些什么呢?

通过复制“默认值”E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED并将其替换为error_reporting =中的等号后当前未注释的内容来关闭E_NOTICE。如果使用CGI或FPM,则重新启动Apache或PHP。确保你编辑的是“正确的”php.ini文件。如果你用Apache运行PHP,正确的选择是Apache,如果用PHP- fpm,选择fpm或PHP- fpm,如果用PHP- cgi,选择cgi,等等。这不是推荐的方法,但如果您有难以编辑的遗留代码,那么它可能是您最好的选择。 关闭文件或文件夹级别的E_NOTICE。如果您有一些遗留代码,但希望以“正确”的方式做事,那么这可能更可取。要做到这一点,你应该咨询Apache 2, Nginx或任何你选择的服务器。在Apache中,您可以在<Directory>中使用php_value。 重写代码,使其更清晰。如果你在转移到生产环境时需要这样做,或者不想让别人看到你的错误,确保你禁用了任何错误显示,只记录你的错误(参见php.ini和你的服务器设置中的display_errors和log_errors)。

扩展选项3:这是最理想的。如果你可以走这条路,你就应该走。如果您最初没有走这条路,请考虑最终通过在开发环境中测试您的代码来移动这条路。在此过程中,去掉~E_STRICT和~E_DEPRECATED,看看将来会出现什么问题。您将看到许多不熟悉的错误,但这将使您在将来需要升级PHP时避免遇到任何不愉快的问题。

这些错误意味着什么?

未定义变量: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';

(额外的小费)

当我遇到这些和其他问题时,我使用了netbeans IDE(免费),它给了我许多警告和注意。其中一些提供了非常有用的建议。这不是一个要求,除了大型项目,我不再使用ide了。我现在更有活力了:)。

错误显示@操作符

对于不需要的和多余的通知,可以使用专用的@操作符来»隐藏«未定义的变量/索引消息。

$var = @($_GET["optional_param"]);

这通常是不鼓励的。新人往往会过度使用它。 对于应用程序逻辑深处的代码(忽略不应该声明的未声明变量)是非常不合适的,例如函数参数或循环中。 isset有一个好处?:或??然而super-supression。通知仍然可以被记录。可以使用set_error_handler("var_dump")来恢复@-hidden通知; 另外,你不应该在初始代码中习惯性地使用/recommend if (isset($_POST["shubmit"]))。 新人不会发现这样的错别字。它只是剥夺了这些情况下的php注意。仅在验证功能后添加@或isset。 首先解决原因。不是通知。 @主要用于$_GET/$_POST输入参数,特别是在它们是可选的情况下。

既然这涵盖了大多数这样的问题,让我们扩展一下最常见的原因:

$_GET / $_POST / $_REQUEST未定义输入

当遇到未定义的索引/偏移量时,你要做的第一件事是检查错字: $count = $_GET["whatnow?"]; 这是每个页面请求中所期望的键名吗? 变量名和数组索引在PHP中是区分大小写的。 其次,如果通知没有明显的原因,使用var_dump或print_r来验证所有输入数组的当前内容: var_dump ($ _GET); var_dump ($ _POST); / / print_r ($ _REQUEST); 两者都将揭示您的脚本是否使用了正确的参数或任何参数调用。 或者使用你的浏览器devtools (F12)检查network选项卡中的请求和参数: POST参数和GET输入将分别显示。 对于$_GET参数,还可以查看中的QUERY_STRING _SERVER print_r (); PHP有一些规则来将非标准参数名称合并到超全局参数中。Apache也可能会进行一些重写。 您还可以以这种方式查看提供的原始$_COOKIES和其他HTTP请求标头。 更明显的是查看浏览器地址栏的GET参数: http://example.org/script.php?id=5&sort=desc name=value在?问号是查询(GET)参数。因此,这个URL可能只会产生$_GET["id"]和$_GET["sort"]。 最后检查你的<form>和<input>声明,如果你期望一个参数但没有收到。 确保每个必需的输入都有一个<input name=FOO> id=或title=属性是不够的。 method=POST表单应该填充$_POST。 而method=GET(或省略它)将产生$_GET变量。 表单也可以提供action=script.php?get=param通过$_GET和剩余的方法=POST字段在$_POST旁边。 对于现代PHP配置(≥5.6),再次使用$_REQUEST['vars']已经变得可行(不流行),它将GET和POST参数混在一起。 如果你正在使用mod_rewrite,那么你应该检查access.log以及启用RewriteLog来找出缺失的参数。

带有_file美元

同样的健全检查适用于文件上传和$_FILES["formname"]。 此外,检查enctype=multipart/form-data 以及<form>声明中的method=POST。 参见:PHP未定义索引错误$_FILES?

$ _COOKIE

$_COOKIE数组永远不会在setcookie()之后填充,而只在后续的HTTP请求中填充。 此外,它们的有效性会超时,它们可以被限制在子域或单个路径上,用户和浏览器可以拒绝或删除它们。

当我们使用一个未设置的变量时,就会发生这些错误。

处理这些问题的最佳方法是在开发时设置错误报告。

设置错误报告:

ini_set('error_reporting', 'on');
ini_set('display_errors', 'on');
error_reporting(E_ALL);

在生产服务器上,错误报告是关闭的,因此,我们不会得到这些错误。

但是,在开发服务器上,我们可以设置错误报告。

为了消除这个错误,我们看到下面的例子:

if ($my == 9) {
 $test = 'yes';  // Will produce an error as $my is not 9.
}
echo $test;

在赋值或使用变量之前,可以将变量初始化为NULL。

因此,我们可以将代码修改为:

$test = NULL;
if ($my == 9) {
 $test = 'yes';  // Will produce an error as $my is not 9.
}
echo $test;

这不会干扰任何程序逻辑,即使$test没有值,也不会产生Notice。

因此,基本上,在开发时将错误报告设置为ON总是更好的。

并修复所有的错误。

在生产中,错误报告应该设置为关闭。

如果你要向API发送数据,只需使用isset():

if(isset($_POST['param'])){
    $param = $_POST['param'];
} else {
    # Do something else
}

如果是由于会话导致的错误,请确保已正确启动会话。