我正在运行一个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 7.0中,现在可以使用空合并操作符:

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

Is等于:

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

PHP 7.0手册

其他回答

可能你使用的是旧的PHP版本,现在升级了PHP,这就是为什么它多年来一直没有任何错误。

在php4之前,如果你使用变量而没有定义它,就不会出现错误,但从php5开始,它会抛出类似上述问题的代码错误。

关于这部分问题:

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

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

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

在PHP 7.0中,现在可以使用空合并操作符:

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

Is等于:

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

PHP 7.0手册