我正在运行 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 建议在开发期间允许 。
处理问题的方法:
建议:声明变量,例如,当您尝试将字符串附加到未定义的变量时。或者使用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'] ?? '';
为 E_NOTICE 设置自定义错误处理程序 ,并将消息从标准输出重定向(可能是日志文件):
set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
禁用报告中的 E_NOTICE。仅排除E_NOTICE
快速方法是:
error_reporting( error_reporting() & ~E_NOTICE )
使用@运算符抑制错误。
注意:强烈建议仅实施第 1 点。
当您(或 PHP)尝试访问数组的未定义索引时,会出现此通知。
处理问题的方法:
在访问索引之前检查索引是否存在。为此,您可以使用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'] : '';
语言构造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);
关于会话的说明:
session, session_start();
需要使用会话放在所有文件中。
@
运算符 对于不需要的和冗余的通知,可以使用专用的@
运算符来隐藏未定义的变量 / 索引消息。
$var = @($_GET["optional_param"]);
isset?:
or ??
super-supression however. Notices still can get logged. And one may resurrect @
-hidden notices with: set_error_handler("var_dump");
if (isset($_POST["shubmit"]))
in your initial code.@
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 inputFirst thing you do when encountering an undefined index/offset, is check for typos:
$count = $_GET["whatnow?"];
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:
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.
<input name=FOO>
id=
or title=
attribute does not suffice.method=POST
form ought to populate $_POST
.method=GET
(or leaving it out) would yield $_GET
variables.action=script.php?get=param
via $_GET and the remaining method=POST
fields in $_POST alongside.$_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
$_FILES["formname"]
.enctype=multipart/form-data
method=POST
in your <form>
declaration.$_COOKIE
$_COOKIE
array is never populated right after setcookie()
, but only on any followup HTTP request.