使用 PHP 的“注意:未定义变量”、“注意:未定义索引”和“注意:未定义偏移”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4261133/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Notice: Undefined variable", "Notice: Undefined index", and "Notice: Undefined offset" using PHP
提问by Pekka
I'm running a PHP script and continue to receive errors like:
我正在运行一个 PHP 脚本并继续收到如下错误:
Notice: Undefined variable: my_variable_name in C:\wamp\www\mypath\index.php on line 10
Notice: Undefined index: my_index C:\wamp\www\mypath\index.php on line 11
注意:未定义变量:第 10 行 C:\wamp\www\mypath\index.php 中的 my_variable_name
注意:第 11 行未定义索引:my_index C:\wamp\www\mypath\index.php
Line 10 and 11 looks like this:
第 10 行和第 11 行如下所示:
echo "My variable value is: " . $my_variable_name;
echo "My index value is: " . $my_array["my_index"];
What is the meaning of these error messages?
这些错误消息的含义是什么?
Why do they appear all of a sudden? I used to use this script for years and I've never had any problem.
为什么它们会突然出现?我曾经使用这个脚本多年,我从来没有遇到过任何问题。
How do I fix them?
我该如何修复它们?
This is a General Reference questionfor people to link to as duplicate, instead of having to explain the issue over and over again. I feel this is necessary because most real-world answers on this issue are very specific.
Related Meta discussion:
这是一个通用参考问题,供人们链接到重复项,而不必一遍又一遍地解释问题。我觉得这是必要的,因为关于这个问题的大多数现实世界的答案都非常具体。
相关元讨论:
采纳答案by Alin Purcaru
Notice: Undefined variable
注意:未定义的变量
From the vast wisdom of the PHP Manual:
来自PHP 手册的丰富智慧:
Relying on the default value of an uninitialized variable is problematic in the case of including one file into another which uses the same variable name. It is also a major security riskwith register_globalsturned on. E_NOTICElevel error is issued in case of working with uninitialized variables, however not in the case of appending elements to the uninitialized array. isset()language construct can be used to detect if a variable has been already initialized. Additionally and more ideal is the solution of empty()since it does not generate a warning or error message if the variable is not initialized.
在将一个文件包含到另一个使用相同变量名的文件中的情况下,依赖未初始化变量的默认值是有问题的。这也是一个重大的安全风险与register_globals的开启。E_NOTICE级别错误是在使用未初始化变量的情况下发出的,但不是在将元素附加到未初始化数组的情况下。isset()语言构造可用于检测变量是否已被初始化。此外,更理想的是empty()的解决方案,因为如果变量未初始化,它不会生成警告或错误消息。
From PHP documentation:
来自PHP 文档:
No warning is generated if the variable does not exist. That means empty()is essentially the concise equivalent to !isset($var) || $var == false.
如果变量不存在,则不会生成警告。这意味着 empty()本质上是等价于!isset($var) || $var == 假。
This means that you could use only empty()
to determine if the variable is set, and in addition it checks the variable against the following, 0
, 0.0
, ""
, "0"
, null
, false
or []
.
这意味着您只能使用empty()
来确定变量是否已设置,此外它还会根据以下内容检查变量,0
, 0.0
, ""
, "0"
, null
,false
或[]
。
Example:
例子:
$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";
});
Test the above snippet in the 3v4l.org online PHP editor
在3v4l.org 在线 PHP 编辑器中测试上述代码段
Although PHP does not require a variable declaration, it does recommend it in order to avoid some security vulnerabilities or bugs where one would forget to give a value to a variable that will be used later in the script. What PHP does in the case of undeclared variables is issue a very low level error, E_NOTICE
, one that is not even reported by default, but the Manual advises to allowduring development.
尽管 PHP 不需要变量声明,但它确实建议这样做,以避免某些安全漏洞或错误,因为人们会忘记为稍后将在脚本中使用的变量赋值。PHP 在未声明变量的情况下所做的是发出一个非常低级别的错误,E_NOTICE
默认情况下甚至不会报告,但手册建议在开发过程中允许。
Ways to deal with the issue:
处理问题的方法:
Recommended:Declare your variables, for example when you try to append a string to an undefined variable. Or use
isset()
/!empty()
to check if they are declared before referencing them, as in://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'] : '';
This has become much cleaner as of PHP 7.0, now you can use the null coalesce operator:
// Null coalesce operator - No need to explicitly initialize the variable. $value = $_POST['value'] ?? '';
Set a custom error handlerfor E_NOTICE and redirect the messages away from the standard output (maybe to a log file):
set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
Disable E_NOTICE from reporting. A quick way to exclude just
E_NOTICE
is:error_reporting( error_reporting() & ~E_NOTICE )
Suppress the error with the @ operator.
推荐:声明您的变量,例如当您尝试将字符串附加到未定义的变量时。或者 在引用它们之前使用
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 合并运算符:
// 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 )
使用@ 运算符抑制错误。
Note:It's strongly recommended to implement just point 1.
注意:强烈建议只实施第 1 点。
Notice: Undefined index / Undefined offset
注意:未定义索引/未定义偏移
This notice appears when you (or PHP) try to access an undefined index of an array.
当您(或 PHP)尝试访问数组的未定义索引时,会出现此通知。
Ways to deal with the issue:
处理问题的方法:
Check if the index exists before you access it. For this you can use
isset()
orarray_key_exists()
://isset() $value = isset($array['my_index']) ? $array['my_index'] : ''; //array_key_exists() $value = array_key_exists('my_index', $array) ? $array['my_index'] : '';
The language construct
list()
may generate this when it attempts to access an array index that does not exist:list($a, $b) = array(0 => 'a'); //or list($one, $two) = explode(',', 'test string');
在访问之前检查索引是否存在。为此,您可以使用
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');
Two variables are used to access two array elements, however there is only one array element, index 0
, so this will generate:
两个变量用于访问两个数组元素,但是只有一个数组元素 index 0
,因此这将生成:
Notice: Undefined offset: 1
注意:未定义的偏移量:1
$_POST
/ $_GET
/ $_SESSION
variable
$_POST
/ $_GET
/$_SESSION
可变
The notices above appear often when working with $_POST
, $_GET
or $_SESSION
. For $_POST
and $_GET
you just have to check if the index exists or not before you use them. For $_SESSION
you have to make sure you have the session started with session_start()
and that the index also exists.
使用$_POST
,$_GET
或时经常出现上述注意事项$_SESSION
。对于$_POST
和$_GET
你只需要检查,如果该索引存在,或不使用它们之前。因为$_SESSION
您必须确保会话开始session_start()
并且索引也存在。
Also note that all 3 variables are superglobalsand are uppercase.
另请注意,所有 3 个变量都是超全局变量并且是大写的。
Related:
有关的:
回答by Ish
Try these
试试这些
Q1: this notice means $varname is not defined at current scope of the script.
Q2: Use of isset(), empty() conditions before using any suspicious variable works well.
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'];
}
Or, as a quick and dirty solution:
或者,作为一个快速而肮脏的解决方案:
// not the best solution, but works
// in your php setting use, it helps hiding site wide notices
error_reporting(E_ALL ^ E_NOTICE);
Note about sessions:
关于会话的注意事项:
When using sessions,
session_start();
is required to be placed inside all files using sessions.
使用会话时,
session_start();
需要放在所有使用会话的文件中。
回答by mario
Error display @
operator
错误显示@
操作符
For undesired and redundant notices, one could use the dedicated @
operatorto ?hide? undefined variable/index messages.
对于不需要的和冗余的通知,可以使用专用@
运算符来 ? 隐藏?未定义的变量/索引消息。
$var = @($_GET["optional_param"]);
- This is usually discouraged. Newcomers tend to way overuse it.
- It's very inappropriate for code deep within the application logic (ignoring undeclared variables where you shouldn't), e.g. for function parameters, or in loops.
- There's one upside over the
isset?:
or??
super-supression however. Notices still can get logged. And one may resurrect@
-hidden notices with:set_error_handler("var_dump");
- Additonally you shouldn't habitually use/recommend
if (isset($_POST["shubmit"]))
in your initial code. - Newcomers won't spot such typos. It just deprives you of PHPs Notices for those very cases. Add
@
orisset
only afterverifying functionality. Fix the cause first. Not the notices.
- Additonally you shouldn't habitually use/recommend
@
is mainly acceptable for$_GET
/$_POST
input parameters, specifically if they're optional.
- 这通常是不鼓励的。新手往往会过度使用它。
- 它非常不适合应用程序逻辑深处的代码(忽略不应该声明的未声明变量),例如函数参数或循环中的代码。
- 然而,超抑制
isset?:
或??
超抑制有一个好处。通知仍然可以被记录。并且可以通过以下方式复活@
隐藏的通知:set_error_handler("var_dump");
- 此外,您不应该
if (isset($_POST["shubmit"]))
在初始代码中习惯性地使用/推荐。 - 新人不会发现这样的错别字。对于那些非常情况,它只是剥夺了您的 PHP 通知。添加
@
或isset
仅在验证功能之后。 先解决原因。不是通知。
- 此外,您不应该
@
主要用于$_GET
/$_POST
输入参数,特别是如果它们是可选的。
And since this covers the majority of such questions, let's expand on the most common causes:
由于这涵盖了大多数此类问题,让我们扩展最常见的原因:
$_GET
/ $_POST
/ $_REQUEST
undefined input
$_GET
/ $_POST
/$_REQUEST
未定义输入
First thing you do when encountering an undefined index/offset, is check for typos:
$count = $_GET["whatnow?"];
- Is this an expected key name and present on eachpage request?
- Variable names andarray indicies are case-sensitive in PHP.
Secondly, if the notice doesn't have an obvious cause, use
var_dump
orprint_r
to verify allinput 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 theQUERY_STRING
inprint_r($_SERVER);
PHP has some rules to coalescenon-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.- Ensure each required input has an
<input name=FOO>
- The
id=
ortitle=
attribute does not suffice. - A
method=POST
form ought to populate$_POST
. - Whereas a
method=GET
(or leaving it out) would yield$_GET
variables. - It's also possible for a form to supply
action=script.php?get=param
via $_GET and the remainingmethod=POST
fields in $_POST alongside. - With modern PHP configurations (≥ 5.6) it has become feasible(not fashionable) to use
$_REQUEST['vars']
again, which mashes GET and POST params.
- Ensure each required input has an
If you are employing mod_rewrite, then you should check both the
access.log
as well as enable theRewriteLog
to figure out absent parameters.
遇到未定义的索引/偏移量时,您要做的第一件事是检查拼写错误:
$count = $_GET["whatnow?"];
- 这是预期的键名并出现在每个页面请求中吗?
- PHP 中的变量名和数组索引区分大小写。
其次,如果通知没有明显的原因,请使用
var_dump
或print_r
验证所有输入数组的当前内容:var_dump($_GET); var_dump($_POST); //print_r($_REQUEST);
两者都会显示您的脚本是否使用正确的参数或任何参数调用。
替代或额外使用您的浏览器 devtools( F12)并检查网络选项卡以获取请求和参数:
POST 参数和 GET 输入将分开显示。
对于
$_GET
参数,您还可以查看QUERY_STRING
inprint_r($_SERVER);
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
。- 而 a
method=GET
(或省略它)会产生$_GET
变量。 - 表单也可以
action=script.php?get=param
通过 $_GET 和method=POST
$_POST 中的其余字段一起提供。 - 使用现代 PHP 配置(≥ 5.6)再次使用变得可行(不流行)
$_REQUEST['vars']
,它混合了 GET 和 POST 参数。
- 确保每个必需的输入都有一个
如果您正在使用 mod_rewrite,那么您应该同时检查
access.log
和启用RewriteLog
以找出缺少的参数。
$_FILES
$_FILES
- The same sanity checks apply to file uploads and
$_FILES["formname"]
. - Moreover check for
enctype=multipart/form-data
- As well as
method=POST
in your<form>
declaration. - See also: PHP Undefined index error $_FILES?
- 相同的健全性检查适用于文件上传和
$_FILES["formname"]
. - 此外检查
enctype=multipart/form-data
- 以及
method=POST
在您的<form>
声明中。 - 另请参阅:PHP 未定义索引错误 $_FILES?
$_COOKIE
$_COOKIE
- The
$_COOKIE
array is never populated right aftersetcookie()
, but only on any followup HTTP request. - Additionally their validity times out, they could be constraint to subdomains or individual paths, and user and browser can just reject or delete them.
- 该
$_COOKIE
数组永远不会在 之后立即填充setcookie()
,而是仅在任何后续 HTTP 请求上填充。 - 此外,它们的有效性超时,它们可能受到子域或单个路径的限制,用户和浏览器可以拒绝或删除它们。
回答by Erik
Generally because of "bad programming", and a possibility for mistakes now or later.
通常是因为“糟糕的编程”,以及现在或以后出错的可能性。
- If it's a mistake, make a proper assignment to the variable first: $varname=0;
- If it really is only defined sometimes, test for it:
if (isset($varname))
, before using it - If it's because you spelled it wrong, just correct that
- Maybe even turn of the warnings in you PHP-settings
- 如果出错,首先对变量进行适当的赋值:$varname=0;
- 如果它真的只是有时定义,请测试它:
if (isset($varname))
,在使用它之前 - 如果是因为你拼错了,就更正一下
- 甚至可能会关闭PHP 设置中的警告
回答by DGM
It means you are testing, evaluating, or printing a variable that you have not yet assigned anything to. It means you either have a typo, or you need to check that the variable was initialized to something first. Check your logic paths, it may be set in one path but not in another.
这意味着您正在测试、评估或打印尚未分配任何内容的变量。这意味着您要么有拼写错误,要么需要先检查变量是否已初始化为某些内容。检查您的逻辑路径,它可能设置在一个路径中,但不在另一个路径中。
回答by Ferenci Zoltán László
I didn't want to disable notice because it's helpful, but wanted to avoid too much typing.
我不想禁用通知,因为它很有帮助,但想避免输入太多。
My solution was this function:
我的解决方案是这个功能:
function ifexists($varname)
{
return(isset($$varname)?$varname:null);
}
So if I want to reference to $name and echo if exists, I simply write:
所以如果我想引用 $name 和 echo 如果存在,我只需写:
<?=ifexists('name')?>
For array elements:
对于数组元素:
function ifexistsidx($var,$index)
{
return(isset($var[$index])?$var[$index]:null);
}
In page if I want to refer to $_REQUEST['name']:
在页面中,如果我想参考 $_REQUEST['name']:
<?=ifexistsidx($_REQUEST,'name')?>
回答by mpyw
The best way for getting input stringis:
获取输入字符串的最佳方法是:
$value = filter_input(INPUT_POST, 'value');
This one-liner is almost equivalent to:
这个单行几乎相当于:
if (!isset($_POST['value'])) {
$value = null;
} elseif (is_array($_POST['value'])) {
$value = false;
} else {
$value = $_POST['value'];
}
If you absolutely want stringvalue, just like:
如果你绝对想要字符串值,就像:
$value = (string)filter_input(INPUT_POST, 'value');
回答by Robbie
In reply to ""Why do they appear all of a sudden? I used to use this script for years and I've never had any problem."
回复“”为什么会突然出现?我曾经使用这个脚本多年,我从来没有遇到过任何问题。”
It is very common for most sites to operate under the "default" error reporting of "Show all errors, but not 'notices' and 'deprecated'". This will be set in php.ini and apply to all sites on the server. This means that those "notices" used in the examples will be suppressed (hidden) while other errors, considered more critical, will be shown/recorded.
大多数站点在“显示所有错误,但不显示'通知'和'已弃用'”的“默认”错误报告下运行是很常见的。这将在 php.ini 中设置并应用于服务器上的所有站点。这意味着示例中使用的那些“通知”将被抑制(隐藏),而其他被认为更严重的错误将被显示/记录。
The other critical setting is the errors can be hidden (i.e. display_errors
set to "off" or "syslog").
另一个关键设置是可以隐藏错误(即display_errors
设置为“关闭”或“系统日志”)。
What will have happened in this case is that either the error_reporting
was changed to also show notices (as per examples) and/or that the settings were changed to display_errors
on screen (as opposed to suppressing them/logging them).
在这种情况下会发生的情况是,要么error_reporting
更改为也显示通知(如示例所示)和/或设置更改为display_errors
在屏幕上显示(而不是抑制它们/记录它们)。
Why have they changed?
他们为什么变了?
The obvious/simplest answer is that someone adjusted either of these settings in php.ini, or an upgraded version of PHP is now using a different php.ini from before. That's the first place to look.
显而易见/最简单的答案是有人在 php.ini 中调整了这些设置中的任何一个,或者升级版本的 PHP 现在正在使用与以前不同的 php.ini。这是第一个看的地方。
However it is also possible to override these settings in
但是,也可以覆盖这些设置
- .htconf (webserver configuration, including vhosts and sub-configurations)*
- .htaccess
- in php code itself
- .htconf(网络服务器配置,包括虚拟主机和子配置)*
- .htaccess
- 在 php 代码中
and any of these could also have been changed.
并且其中任何一个也可能被更改。
There is also the added complication that the web server configuration can enable/disable .htaccess directives, so if you have directives in .htaccess that suddenly start/stop working then you need to check for that.
还有一个额外的复杂性,即 Web 服务器配置可以启用/禁用 .htaccess 指令,因此如果您在 .htaccess 中有突然启动/停止工作的指令,那么您需要检查它。
(.htconf / .htaccess assume you're running as apache. If running command line this won't apply; if running IIS or other webserver then you'll need to check those configs accordingly)
(.htconf / .htaccess 假设您以 apache 身份运行。如果运行命令行,这将不适用;如果运行 IIS 或其他网络服务器,则您需要相应地检查这些配置)
Summary
概括
- Check
error_reporting
anddisplay_errors
php directives in php.ini has not changed, or that you're not using a different php.ini from before. - Check
error_reporting
anddisplay_errors
php directives in .htconf (or vhosts etc) have not changed - Check
error_reporting
anddisplay_errors
php directives in .htaccess have not changed - If you have directive in .htaccess, check if they are still permitted in the .htconf file
- Finally check your code; possibly an unrelated library; to see if
error_reporting
anddisplay_errors
php directives have been set there.
- php.ini 中的检查
error_reporting
和display_errors
php 指令没有改变,或者您没有使用与以前不同的 php.ini。 - .htconf(或 vhosts 等)中的Check
error_reporting
和display_errors
php 指令没有改变 - .htaccess 中的Check
error_reporting
和display_errors
php 指令没有改变 - 如果您在 .htaccess 中有指令,请检查 .htconf 文件中是否仍然允许使用它们
- 最后检查你的代码;可能是一个不相关的图书馆;查看是否在那里设置了
error_reporting
和display_errors
php 指令。
回答by Roger
Its because the variable '$user_location' is not getting defined. If you are using any if loop inside which you are declaring the '$user_location' variable then you must also have an else loop and define the same. For example:
这是因为变量 '$user_location' 没有被定义。如果您使用任何 if 循环在其中声明 '$user_location' 变量,那么您还必须有一个 else 循环并定义相同的循环。例如:
$a=10;
if($a==5) { $user_location='Paris';} else { }
echo $user_location;
The above code will create error as The if loop is not satisfied and in the else loop '$user_location' was not defined. Still PHP was asked to echo out the variable. So to modify the code you must do the following:
上面的代码将创建错误,因为不满足 if 循环并且在 else 循环中未定义“$user_location”。仍然要求 PHP 回显变量。因此,要修改代码,您必须执行以下操作:
$a=10;
if($a==5) { $user_location='Paris';} else { $user_location='SOMETHING OR BLANK'; }
echo $user_location;
回答by Shahin Mammadzada
the quick fix is to assign your variable to null at the top of your code
快速修复是在代码顶部将变量分配为 null
$user_location = null;