PHP:“注意:未定义的variables”,“注意:未定义的索引”和“注意:未定义的偏移量”
我正在运行一个PHP脚本,并不断收到像这样的错误:
注意:未定义的variables:第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"]; 这些错误是什么意思?
他们为什么突然出现? 我曾经使用这个脚本多年,我从来没有任何问题。
我需要做些什么来解决它们?
这是一个一般性的参考问题 ,人们可以将其链接为重复,而不必一遍又一遍地解释这个问题。 我觉得这是必要的,因为在这个问题上的大多数现实世界的答案是非常具体的。
相关元讨论:
- 关于重复性问题可以做些什么?
- “参考问题”是否有意义?
注意:未定义的variables
从PHP手册的广泛的智慧:
在将一个文件包含到另一个使用相同variables名的文件中时,依赖于未初始化variables的默认值是有问题的。 这也是一个重要的安全风险 ,开启register_globals 。 在使用未初始化的variables的情况下会发出E_NOTICE级别的错误,但是不会在将元素追加到未初始化的数组的情况下。 isset()语言结构可用于检测variables是否已被初始化。 此外,更理想的是empty()的解决scheme,因为如果variables未初始化,它不会生成警告或错误消息。
从PHP文档 :
如果variables不存在,则不会生成警告。 这意味着empty()实质上就是!isset($ var)||的简洁等价物 $ var == false 。
 这意味着你只能使用empty()来确定variables是否被设置,另外它会检查variables是否为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编辑器中testing上面的代码片段
 尽pipePHP不需要variables声明,但是为了避免一些安全漏洞或者错误,人们会忘记给稍后在脚本中使用的variables赋予一个值。 在未声明variables的情况下,PHP会发出一个非常低的错误E_NOTICE ,一个默认情况下甚至没有被报告的错误,但是手册build议在开发过程中允许 。 
处理这个问题的方法:
- 
build议:声明你的variables,例如当你尝试将一个string附加到一个未定义的variables。 或者使用 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设置自定义error handling程序 ,并将消息从标准输出(可能是日志文件)中redirect: set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
- 
禁止报告E_NOTICE。 排除 E_NOTICE快速方法是:error_reporting( error_reporting() & ~E_NOTICE )
- 
用@运算符来抑制错误。 
注意:强烈build议仅实施第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');
 两个variables用于访问两个数组元素,但是只有一个数组元素,索引0 ,所以这将生成: 
注意:未定义偏移量:1
  $_POST / $_GET / $_SESSIONvariables 
 上述注意事项通常在使用$_POST , $_GET或$_SESSION 。 对于$_POST和$_GET您只需检查索引是否存在,然后再使用它们。 对于$_SESSION你必须确保你的session是以session_start()开始的,并且索引也是存在的。 
还要注意,所有3个variables都是超全球variables 。 这意味着他们需要用大写字母书写。
有关:
- 注意:未定义的variables
- 注意:未定义的索引
试试这些
Q1:这个通知意味着$ varname没有在脚本的当前范围内定义。
Q2:在使用任何可疑variables之前,使用isset(),empty()条件很好。
 // recommended solution $user_name = $_SESSION['user_name']; if (empty($user_name)) $user_name = ''; OR // just define at the top of the script index.php $user_name = ''; $user_name = $_SESSION['user_name']; OR $user_name = $_SESSION['user_name']; if (!isset($user_name)) $user_name = ''; 
快速解决scheme:
 // not the best solution, but works // in your php setting use, it helps hiding site wide notices error_reporting(E_ALL ^ E_NOTICE); 
关于会议的注意
- 
在使用会话时, session_start();需要被放置在使用会话的所有文件中。
 一个(通常不鼓励)的select是错误抑制运算符 @ 。 这是closures不需要的通知和警告的特定语言结构,但应小心使用。 
 首先,它使用isset会导致微观性能损失。 这在现实世界的应用中是不可测量的,但是应该在数据量大的迭代中考虑。 其次它可能会阻碍debugging,但同时抑制错误实际上传递到自定义error handling程序(不像isset装饰expression式)。 
这意味着您正在testing,评估或打印尚未分配任何内容的variables。 这意味着你要么有一个错字,要么你需要检查variables是否被初始化了。 检查你的逻辑path,它可能被设置在一个path中,而不是另一个。
一般是因为“糟糕的编程”,以及现在或以后出现错误的可能性。
- 如果这是一个错误,请首先对variables进行适当的分配:$ varname = 0;
- 如果它确实有时只是定义,那么在使用它之前testing它:if(isset($ varname))….
- 如果是因为你拼错了,就纠正一下
- 甚至可能会在你的PHP设置中出现警告
我不想禁用通知,因为它是有帮助的,但是想要避免太多的input。
我的解决scheme是这个function:
 function ifexists($varname) { return(isset($$varname)?$varname:null); } 
所以,如果我想引用$ name和回声如果存在,我只是写:
 <?=ifexists('name')?> 
对于数组元素:
 function ifexistsidx($var,$index) { return(isset($var[$index])?$var[$index]:null); } 
在页面中,如果我想引用$ _REQUEST ['name']:
 <?=ifexistsidx($_REQUEST,'name')?> 
获取inputstring的最佳方法是:
 $value = filter_input(INPUT_POST, 'value'); 
这一行代码几乎相当于:
 if (!isset($_POST['value'])) { $value = null; } elseif (is_array($_POST['value'])) { $value = false; } else { $value = $_POST['value']; } 
如果你绝对想要string值,就像:
 $value = (string)filter_input(INPUT_POST, 'value'); 
因为variables'$ user_location'没有被定义。 如果你正在使用任何if循环,你在声明'$ user_location'variables,那么你还必须有一个else循环,并定义相同的。 例如:
 $a=10; if($a==5) { $user_location='Paris';} else { } echo $user_location; 
上面的代码会产生错误,因为if循环没有被满足,而在else循环中没有定义'$ user_location'。 仍然PHP被要求回显variables。 所以要修改代码,您必须执行以下操作:
 $a=10; if($a==5) { $user_location='Paris';} else { $user_location='SOMETHING OR BLANK'; } echo $user_location; 
回答“为什么他们突然出现? 我曾经使用这个脚本多年,我从来没有任何问题。“
大多数网站在“显示所有错误,但不是”通知“和”不推荐“的”默认“错误报告下运行是非常常见的。 这将在php.ini中设置并应用于服务器上的所有站点。 这意味着这些例子中使用的“通知”将被抑制(隐藏),而其他被认为更重要的错误将被显示/logging。
 另一个关键设置是可以隐藏错误(即将display_errors设置为“off”或“syslog”)。 
 在这种情况下会发生什么事情是, error_reporting被更改为也显示通知(根据示例)和/或设置被更改为屏幕上的display_errors (而不是压制他们/logging他们)。 
他们为什么改变了?
最明显/最简单的答案是,有人调整了php.ini中的这些设置,或者PHP的升级版本现在正在使用与之前不同的php.ini。 这是第一个看的地方。
但是也可以在这里覆盖这些设置
- .htconf(networking服务器configuration,包括虚拟主机和子configuration)*
- 的.htaccess
- 在PHP代码本身
而其中的任何一个也可能已经改变了。
Web服务器configuration可以启用/禁用.htaccess指令也会增加复杂性,所以如果你在.htaccess中有突然启动/停止工作的指令,那么你需要检查。
(.htconf / .htaccess假设你运行的是Apache,如果运行命令行,这将不适用;如果运行IIS或其他networking服务器,那么你需要检查这些configuration)
概要
-  检查php.ini中的error_reporting和display_errorsphp指令没有改变,或者你没有使用从前的不同的php.ini。
-  检查.htconf(或虚拟主机等)中的error_reporting和display_errorsphp指令没有改变
-  在.htaccess中检查error_reporting和display_errorsphp指令没有改变
- 如果您在.htaccess中有指令,请检查它们是否仍然在.htconf文件中被允许
-  最后检查你的代码; 可能是一个无关的图书馆; 看看是否在那里设置了error_reporting和display_errorsphp指令。
快速解决方法是将您的variables分配给代码顶部的空值
 $user_location = null; 
我曾经诅咒这个错误,但它可以帮助提醒你逃避用户input。
例如,如果你认为这很聪明,简写代码:
 // Echo whatever the hell this is <?=$_POST['something']?> 
…再想一想! 更好的解决scheme是:
 // If this is set, echo a filtered version <?=isset($_POST['something']) ? html($_POST['something']) : ''?> 
  (我使用自定义html()函数来转义字符,你的里程可能会有所不同) 
我用所有的时间自己有用的函数exst() ,它会自动声明variables。
你的代码将是 –
 $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; } 
 用一种非常简单的语言 。 
 错误的是你正在使用一个variables$user_location这是你以前没有定义,它没有任何价值因此,我build议你在 使用它之前请声明这个variables,例如: 
 $user_location = ''; 
  要么 
 $user_location = 'Los Angles'; 
这是你可以面对的一个非常常见的错误。所以不要担心只是声明variables和享受编码 。
在PHP 7.0中,现在可以使用Null合并运算符:
 echo "My index value is: " . ($my_array["my_index"] ?? ''); 
等于:
 echo "My index value is: " . (isset($my_array["my_index"]) ? $my_array["my_index"] : ''); 
PHP手册PHP 7.0
为什么不把事情简单化?
 <?php error_reporting(E_ALL); // making sure all notices are on function idxVal(&$var, $default = null) { return empty($var) ? $var = $default : $var; } echo idxVal($arr['test']); // returns null without any notice echo idxVal($arr['hey ho'], 'yo'); // returns yo and assigns it to array index, nice ?> 
这是为什么发生?
 随着时间的推移,PHP已经成为一种更安全的语言。 默认情况下,默认closures的设置现在处于打开状态。 一个完美的例子是E_STRICT ,从PHP 5.4.0开始默认开启。 
 此外,根据PHP文档,通过defualt, E_NOTICE在php.ini中被禁用。  PHP文档build议打开它的debugging目的 。 但是,当我从Ubuntu存储库下载PHP时(从BitNami的Windows堆栈下载),我还看到了其他的东西。 
 ; 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实际上设置为生产值,而不是默认值。 这有点令人困惑,并没有logging在php.ini之外,所以我没有在其他发行版上进行validation。 
但是,要回答你的问题,这个错误现在不会popup,因为:
- 
您安装了PHP并且新的默认设置有点不完善,但不排除 E_NOTICE。
- 
类似未定义variables和未定义索引的 E_NOTICE警告实际上有助于使代码更清洁,更安全。 我可以告诉你,几年前,保持E_NOTICE启用迫使我声明我的variables。 这使得它很容易学习C,在那里没有声明variables是一个麻烦大得多。
我可以做些什么?
- 
通过复制“默认值” E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATEDclosuresE_NOTICE,并将其replace为当前在error_reporting =的等号之后未注释的内容。 如果使用CGI或FPM,请重新启动Apache或PHP。 确保你正在编辑“正确的”php.ini。 正确的是Apache,如果你使用Apache运行PHP,运行PHP-FPM的fpm或php-fpm,运行PHP-CGI的CGI等。这不是推荐的方法,但是如果你有遗留的代码,非常难以编辑,那么这可能是你最好的select。
- 
closures文件或文件夹级别的 E_NOTICE。 如果你有一些遗留的代码,但是想做“正确”的事情,这可能会更好。 要做到这一点,你应该咨询Apache2,nginx,或任何您select的服务器。 在Apache中,您可以使用<Directory>php_value。
- 
重写你的代码更清洁。 如果您在移至生产环境时需要执行此操作,或者不希望有人看到您的错误,请确保您禁用了任何错误显示,并且只logging错误(请参阅php.ini中的 display_errors和log_errors以及您的服务器设置)。
 扩大选项3:这是理想的。 如果你可以走这条路,你应该。 如果你最初不走这条路线,最好考虑在开发环境中testing你的代码。 当你在这里,摆脱~E_STRICT和~E_DEPRECATED ,看看未来可能出现什么问题。 你会看到很多不熟悉的错误,但是当你将来需要升级PHP的时候,它会阻止你有任何不愉快的问题。 
什么是错误意味着什么?
  Undefined variable: my_variable_name – 在使用前没有定义variables时发生。 当PHP脚本执行时,它在内部只是一个空值。 但是,在哪种情况下,您需要在定义之前检查一个variables? 最终,这是一个“草率代码”的论点。 作为一名开发人员,我可以告诉你,当我看到一个开源项目时,我喜欢这个项目,variables被定义为可以定义的范围。 它可以更容易地告诉将来会popup哪些variables,并使读取/学习代码更容易。 
 function foo() { $my_variable_name = ''; //.... if ($my_variable_name) { // perform some logic } } 
  Undefined index: 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; 
另一种select是在函数的顶部声明一个空数组。 这并不总是可能的。
 $my_array = array( 'my_index' => '' ); //... $my_array['my_index'] = 'new string'; 
(附加提示)
-  当我遇到这些和其他问题时,我使用了NetBeans IDE (免费),它给了我很多警告和通知。 其中一些提供非常有用的提示。 这不是要求,除了大型项目,我不再使用IDE。 我现在更多是一个vim人:)。
未定义的索引意味着在你请求不可用数组索引的数组中
 <?php $newArray[] = {1,2,3,4,5}; print_r($newArray[5]); ?> 
未定义的variables意味着你已经完全没有使用现有的variables,或者没有用这个名字来定义或初始化variables
 <?php print_r($myvar); ?> 
未定义的偏移量表示数组中您已经要求不存在的键。 而解决scheme是在使用前检查
 php> echo array_key_exists(1, $myarray); 
关于这部分问题:
他们为什么突然出现? 我曾经使用这个脚本多年,我从来没有任何问题。
没有明确的答案,但这里有一些可能的解释,为什么设置可以“突然”改变:
- 
您已经将PHP升级到新版本,可以使用其他默认值error_reporting,display_errors或其他相关设置。 
- 
您已经删除或引入了一些代码(可能在依赖项中),在运行时使用 ini_set()或error_reporting()(在代码中search这些代码)
- 
您更改了networking服务器configuration(假设Apache在这里) .htaccess文件和虚拟主机configuration也可以操纵php设置。
- 
通常不会显示/报告通知(请参阅PHP手册 ),因此在设置服务器时可能会由于某些原因(文件权限)而无法加载php.ini文件,而且您的默认设置。 后来,“错误”已经被解决(不小心),现在它可以加载正确的php.ini文件,并设置error_reporting来显示通知。 
 如果使用类,你需要确保你使用$this引用成员variables: 
 class Person { protected $firstName; protected $lastName; public function setFullName($first, $last) { // Correct $this->firstName = $first; // Incorrect $lastName = $last; // Incorrect $this->$lastName = $last; } } 
为什么会抛出一个未定义的索引通知的另一个原因是从数据库查询中省略了一列。
即:
 $query = "SELECT col1 FROM table WHERE col_x = ?"; 
然后尝试访问循环内更多的列/行。
即:
 print_r($row['col1']); print_r($row['col2']); // undefined index thrown 
 或者在一个while循环中: 
 while( $row = fetching_function($query) ) { echo $row['col1']; echo "<br>"; echo $row['col2']; // undefined index thrown echo "<br>"; echo $row['col3']; // undefined index thrown } 
还有一点需要注意的是,在* NIX OS和Mac OS X上,事情是区分大小写的。
请参考下列问答:
- 
MySQL中的表名是否区分大小写? 
- 
查询中的大小写敏感的表名 
- 
MySql – 不同服务器中表格的大小写敏感问题 
也许你是使用旧的PHP版本,直到现在升级PHP这是它的工作原因没有任何错误,直到现在从几年。 直到PHP4有没有错误,如果你使用variables没有定义它,但从PHP5起,它会抛出错误代码提到的问题。
在处理文件时,需要一个合适的enctype和一个POST方法,如果不包含在表单中,将触发未定义的索引通知。
手册陈述了以下基本语法:
HTML
 <!-- The data encoding type, enctype, MUST be specified as below --> <form enctype="multipart/form-data" action="__URL__" method="POST"> <!-- MAX_FILE_SIZE must precede the file input field --> <input type="hidden" name="MAX_FILE_SIZE" value="30000" /> <!-- Name of input element determines name in $_FILES array --> Send this file: <input name="userfile" type="file" /> <input type="submit" value="Send File" /> </form> 
PHP
 <?php // In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used instead // of $_FILES. $uploaddir = '/var/www/uploads/'; $uploadfile = $uploaddir . basename($_FILES['userfile']['name']); echo '<pre>'; if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { echo "File is valid, and was successfully uploaded.\n"; } else { echo "Possible file upload attack!\n"; } echo 'Here is some more debugging info:'; print_r($_FILES); print "</pre>"; ?> 
参考: