我正在运行一个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已经成为一种更加关注安全的语言。以前默认关闭的设置现在默认打开了。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了。我现在更有活力了:)。

其他回答

我问了一个关于这个问题的问题,我被推荐到这篇文章,上面写着:

这个问题已经有了答案: “Notice: Undefined variable”、“Notice: Undefined index”、“Notice: Undefined index” 未定义的偏移量”使用PHP

我在这里分享我的问题和解决方案:

这是错误:

第154行就是问题所在。第154行是这样的

153    foreach($cities as $key => $city){
154        if(($city != 'London') && ($city != 'Madrid') && ($citiesCounterArray[$key] >= 1)){

我认为问题是我正在为变量$city写if条件,它不是键,而是$key => $city中的值。第一,你能否证实这是否是警告的原因?其次,如果这是问题所在,为什么我不能根据值编写条件呢?我需要用键来写条件吗?

更新1:问题是当执行$citiesCounterArray[$key]时,有时$key对应的是一个在$citiesCounterArray数组中不存在的键,但根据我的循环数据,情况并非总是如此。我需要的是设置一个条件,以便如果数组中存在$key,则运行代码,否则跳过它。

更新2:这是我如何通过使用array_key_exists()修复它:

foreach($cities as $key => $city){
    if(array_key_exists($key, $citiesCounterArray)){
        if(($city != 'London') && ($city != 'Madrid') && ($citiesCounterArray[$key] >= 1)){

关于这部分问题:

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

没有明确的答案,但这里有一些可能的解释,为什么设置可以“突然”改变:

您已经将PHP升级到一个新的版本,该版本可以为error_reporting、display_errors或其他相关设置设置其他默认值。 您已经删除或引入了一些在运行时使用ini_set()或error_reporting()设置相关设置的代码(可能是在依赖项中)(在代码中搜索这些代码) 你改变了web服务器配置(假设这里是apache): .htaccess文件和vhost配置也可以操作php设置。 通常通知不会被显示/报告(参见PHP手册) 因此,在设置服务器时,php.ini文件可能因为某些原因(文件权限??)而无法加载,而您使用的是默认设置。稍后,“错误”已经解决(意外),现在它可以加载正确的php.ini文件与error_reporting设置显示通知。

错误显示@操作符

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

$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请求中填充。 此外,它们的有效性会超时,它们可以被限制在子域或单个路径上,用户和浏览器可以拒绝或删除它们。

注意/警告:未定义变量

尽管PHP不需要变量声明,但它还是推荐这样做,以避免一些安全漏洞或错误,例如忘记为稍后将在脚本中使用的变量赋值。PHP在未声明变量的情况下所做的是发出一个E_WARNING级别的错误。

这个警告可以帮助程序员发现拼写错误的变量名。此外,未初始化的变量还有其他可能的问题。正如PHP手册中所述,

在将一个文件包含到另一个使用相同变量名的文件中时,依赖未初始化变量的默认值是有问题的。

表示在主文件中未初始化,此变量可能被包含文件中的变量重写,这可能导致不可预知的结果。为了避免这种情况,最好对php文件中的所有变量进行初始化

处理这个问题的方法:

建议:声明你的变量,例如当你试图将一个字符串附加到一个未定义的变量。或者使用isset()在引用它们之前检查它们是否被声明,如下所示: //初始化变量 $value = "";/ /初始化值;0表示int,[]表示数组,等等。 echo $价值;//没有错误 用空合并运算符抑制错误。 //空合并运算符 Echo $value ??”; 对于古老的PHP版本(< 7.0),可以使用带三元的isset() 返回isset($value) ?$value: "; 但是要注意,它本质上仍然是一个错误抑制,尽管只是针对一个特定的错误。因此,它可能会阻止PHP通过标记一个统一变量来帮助您。 使用@操作符抑制错误。因为历史原因留在这里,但说真的,这不应该发生。

注意:强烈建议只实现第1点。

注意:未定义索引/未定义偏移/警告:未定义数组键

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

处理这个问题的方法都差不多:

建议:声明你的数组元素: //初始化变量 $array['value'] = "";/ /初始化值;0表示int,[]表示数组,等等。 echo $数组(“价值”);//没有错误 用空合并运算符"抑制错误: echo $_POST['value'] ?”; 对于数组,这个操作符更合理,因为它可以用于您无法控制的外部变量。因此,可以考虑将它仅用于外部变量,例如$_POST / $_GET / $_SESSION或JSON输入。而所有内部数组最好先进行预定义/初始化。 更好的是,验证所有输入,将其分配给局部变量,并在代码中自始至终使用它们。所以你要访问的每个变量都是故意存在的。

相关:

注意:未定义变量 注意:未定义索引

我一直使用自己的有用函数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;
}