提问



我正在运行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手册的广泛智慧:[127] [128] [129]



  在将一个文件包含到另一个使用相同变量名称的文件的情况下,依赖于未初始化变量的默认值是有问题的。打开register_globals也是一个主要的安全风险。如果使用未初始化的变量,则会发出E_NOTICE级别错误,但是在未初始化的数组中附加元素时则不会。 isset()语言构造可用于检测变量是否已经初始化。另外,更理想的是empty()的解决方案,因为如果未初始化变量,它不会生成警告或错误消息。 [130] [131] [132] [133] [134]



来自PHP文档:[135]



  如果变量不存在,则不会生成警告。这意味着
      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编辑器[136]中测试上面的片段


虽然PHP不需要变量声明,但它确实推荐它,以避免一些安全漏洞或错误,人们会忘记为稍后将在脚本中使用的变量赋值。 PHP在未声明变量的情况下所做的是发出一个非常低级别的错误,E_NOTICE,默认情况下甚至没有报告,但手册建议在开发过程中允许。[137]


处理问题的方法:



  1. 推荐:声明您的变量,例如当您尝试将字符串附加到未定义的变量时。或者使用isset()/!empty()检查它们是否在引用之前声明,如:[138] [139]


    //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运算符:[140]


    // Null coalesce operator - No need to explicitly initialize the variable.
    $value = $_POST['value'] ?? '';
    

  2. 为E_NOTICE设置自定义错误处理程序,并将消息重定向远离标准输出(可能是日志文件):[141]


    set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
    

  3. 禁止报告E_NOTICE。仅排除E_NOTICE的快速方法是:


    error_reporting( error_reporting() & ~E_NOTICE )
    

  4. 使用@运算符抑制错误。[142]



注意:强烈建议仅执行第1点。


注意:未定义的索引/未定义的偏移量



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


处理问题的方法:



  1. 在访问索引之前检查索引是否存在。为此你可以使用isset()array_key_exists():[143] [144]


    //isset()
    $value = isset($array['my_index']) ? $array['my_index'] : '';
    //array_key_exists()
    $value = array_key_exists('my_index', $array) ? $array['my_index'] : '';
    

  2. 语言构造list()在尝试访问不存在的数组索引时可能会生成此内容:[145]


    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()开始会话并且索引也存在。[146]


另请注意,所有3个变量都是超全局变量并且是大写的。[147]


有关:



  • 注意:未定义的变量

  • 注意:未定义的索引


其它参考1


试试这些



  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_start();放在所有文件中。

  • http://php.net/manual/en/features.sessions.php [150]


其它参考2


一个(通常是不鼓励的)替代方案是误差抑制算子@。它是一种特定的语言结构,可以关闭不需要的通知和警告,但应谨慎使用。[151]


首先,它使用isset导致微观性能损失。这在现实世界的应用程序中是不可测量的,但应该在数据繁重的迭代中考虑。其次它可能阻碍调试,但同时抑制错误实际上传递给自定义错误处理程序(与isset修饰表达式不同)。

其它参考3


这意味着您正在测试,评估或打印尚未分配任何内容的变量。这意味着您要么输入错误,要么需要先检查变量是否已初始化为某些内容。检查您的逻辑路径,它可以设置在一个路径中,但不能设置在另一个路径中。

其它参考4


一般是因为糟糕的编程,现在或以后都有可能出错。



  1. 如果这是一个错误,请先对变量进行正确的赋值:$ varname=0;

  2. 如果确实只是有时定义,请在使用前测试它if (isset($varname))

  3. 如果是因为你拼错了,那就纠正

  4. 甚至可能会在您 PHP设置
  5. 中关闭警告

其它参考5


我不想禁用通知,因为它有用,但是想避免太多打字。


我的解决方案是这个功能:


function ifexists($varname)
{
  return(isset($$varname)?$varname:null);
}


所以,如果我想引用$ name和echo if exists,我只需写:


<?=ifexists('name')?>


对于数组元素:


function ifexistsidx($var,$index)
{
  return(isset($var[$index])?$var[$index]:null);
}


在页面中,如果我想引用$ _REQUEST [[name]]:


<?=ifexistsidx($_REQUEST,'name')?>

其它参考6


获取输入字符串的最佳方法是:


$value = filter_input(INPUT_POST, 'value');


这个单线几乎相当于:


if (!isset($_POST['value'])) {
    $value = null;
} elseif (is_array($_POST['value'])) {
    $value = false;
} else {
    $value = $_POST['value'];
}


如果你绝对想要字符串值,就像:


$value = (string)filter_input(INPUT_POST, 'value');

其它参考7


这是因为变量$ user_location没有得到定义。如果您正在使用任何if循环来声明$ user_location变量,那么您还必须有一个else循环并定义相同的循环。例如:


$a=10;
if($a==5) { $user_location='Paris';} else { }
echo $user_location;


上面的代码将创建错误,因为不满足if循环,并且在else循环中没有定义$ user_location。仍然要求PHP回应变量。因此,要修改代码,您必须执行以下操作:


$a=10;
if($a==5) { $user_location='Paris';} else { $user_location='SOMETHING OR BLANK'; }
echo $user_location;

其它参考8


回复他们为什么突然出现?我以前使用这个脚本多年,我从来没有遇到任何问题。


大多数站点在显示所有错误,但不是通知和已弃用的默认错误报告下运行是很常见的。这将在php.ini中设置并应用于服务器上的所有站点。这意味着示例中使用的那些通知将被抑制(隐藏),而其他错误(被认为更为关键)将被显示/记录。


另一个关键设置是可以隐藏错误(即display_errors设置为off或syslog)。


在这种情况下会发生的是,error_reporting被更改为也显示通知(根据示例)和/或设置在屏幕上更改为display_errors(而不是抑制它们/记录它们)。


他们为什么要改变?


显而易见/最简单的答案是有人在php.ini中调整了这些设置中的任何一个,或者PHP的升级版现在使用了之前不同的php.ini。那是第一个看的地方。


但是,也可以覆盖这些设置



  • .htconf(网络服务器配置,包括虚拟主机和子配置)*

  • 的.htaccess

  • 在PHP代码本身



其中任何一个也可以改变。


还有一个额外的复杂性,即Web服务器配置可以启用/禁用.htaccess指令,因此如果.htaccess中的指令突然启动/停止工作,那么您需要检查它。


(.htconf/.htaccess假设您正在以apache身份运行。如果运行命令行,这将不适用;如果运行IIS或其他Web服务器,那么您将需要相应地检查这些配置)


摘要



  • 检查error_reportingdisplay_errors php.ini中的php指令没有改变,或者你之前没有使用过不同的php.ini。

  • 检查error_reportingdisplay_errors .htconf(或vhosts等)中的php指令没有改变

  • 检查。error_reportingdisplay_errors .htaccess中的php指令没有改变

  • 如果您在.htaccess中有指令,请检查.htconf文件中是否仍然允许它们

  • 最后检查你的代码;可能是一个无关的图书馆;看看那里是否设置了error_reportingdisplay_errors php指令。


其它参考9


快速解决方法是在代码顶部将变量赋值为null


$user_location = null;

其它参考10


我曾经诅咒这个错误,但提醒你逃避用户输入会很有帮助。


例如,如果您认为这是一个聪明的简写代码:


// Echo whatever the hell this is
<?=$_POST['something']?>


...再想一想!更好的解决方案是:


// If this is set, echo a filtered version
<?=isset($_POST['something']) ? html($_POST['something']) : ''?>


(我使用自定义html()功能来逃避角色,你的里程可能会有所不同)

其它参考11


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

其它参考12


在一个非常简单的语言。。错误是你使用的变量$user_location是你之前没有定义的,它没有任何价值所以我建议你请声明此变量 之前使用,例如:
$user_location = '';

$user_location = 'Los Angles';

这是您可以面对的一个非常常见的错误。所以不要担心只声明变量和享受编码

其它参考13


在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 [152]

其它参考14


为什么不把事情简单化?


<?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

?>

其它参考15


为什么会发生这种情况?



随着时间的推移,PHP已成为一种更加注重安全性的语言。默认情况下,以前关闭的设置现在处于打开状态。一个完美的例子就是E_STRICT,从PHP 5.4.0开始默认打开。 [153]


此外,根据PHP文档,通过defualt,[[。E_NOTICE在php.ini中被禁用。 PHP文档建议将其打开以进行调试。但是,当我从Ubuntu存储库下载PHP时 - 以及从BitNami的Windows堆栈中下载 - 我看到了别的东西。[154]


; 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实际上设置为生产值,而不是默认设置为默认值。这有点令人困惑,并没有在php.ini之外记录,因此我在其他发行版上验证了


但是,要回答您的问题,此错误会在之前未弹出时突然显示,因为:



  1. 您安装了PHP并且新的默认设置记录较差,但不排除E_NOTICE

  2. E_NOTICE警告,如未定义的变量和未定义的索引实际上有助于使您的代码更清除,更安全。我可以告诉你,多年前,保持E_NOTICE使我不得不声明我的变量。它使得学习C更容易,其中没有声明变量更令人讨厌。



我可以做些什么?




  1. 通过复制默认值E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED关闭E_NOTICE并将其替换为error_reporting =中等号后当前取消注释的内容。如果使用CGI或FPM,请重新启动Apache或PHP。确保您正在编辑正确的php.ini。如果您使用Apache运行PHP,那么正确的将是Apache,如果运行PHP-FPM则运行fpm或php-fpm,如果运行PHP-CGI则运行cgi,等等。这不是推荐的方法,但如果您有遗留代码s编辑非常困难,那么这可能是你最好的选择。

  2. 关闭文件或文件夹级别的E_NOTICE。如果您有一些遗留代码但希望以正确方式执行操作,这可能更为可取。要做到这一点,您应该咨询Apache2,nginx或您选择的服务器。在Apache中,你会在<Directory>中使用php_value

  3. 重写您的代码以使其更清晰。如果您在迁移到生产环境时需要执行此操作,或者不希望有人看到您的错误,请确保您禁用任何错误显示,并且只有记录您的错误(请参阅display_errorslog_errors在php.ini和您的服务器设置中)。



扩展选项3:这是理想的选择。如果你能走这条路,你应该。如果您最初没有使用此路由,请考虑通过在开发环境中测试代码来最终移动此路由。当你了解它时,摆脱~E_STRICT~E_DEPRECATED来看看未来会出现什么问题。你会看到很多不熟悉的错误,但它会停止当你将来需要升级PHP时,你会遇到任何不愉快的问题。


错误意味着什么?



Undefined variable: my_variable_name - 在使用前未定义变量时会发生这种情况。执行PHP脚本时,它在内部只假定一个空值。但是,在哪种情况下,您需要在定义变量之前检查它?最终,这是草率代码的论据。作为开发人员,我可以告诉你,当我看到一个开源项目时,我喜欢它,在这个项目中,变量被定义为可以定义的范围内的高位。它可以更容易地告诉将来会弹出哪些变量,并且更容易阅读/学习代码。


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;   


另一种选择是在函数顶部声明一个空数组。这并不总是可行的。


$my_array = array(
    'my_index' => ''
);

//...

$my_array['my_index'] = 'new string';


(附加提示)




  • 当我遇到这些问题和其他问题时,我使用了NetBeans IDE(免费),它给了我许多警告和通知。其中一些提供非常有用的提示。这不是必需的,除了大型项目之外,我不再使用IDE。我现在更多的是vim人。)。


其它参考16


未定义索引意味着您在请求不可用数组索引的数组中[[例如[155]


<?php 

$newArray[] = {1,2,3,4,5};
print_r($newArray[5]);

?>


未定义的变量意味着您完全不使用现有变量,或者未使用该名称定义或初始化该变量


<?php print_r($myvar); ?>


undefined offset表示您已请求不存在的键。而且
解决方案是在使用前检查


php> echo array_key_exists(1, $myarray);

其它参考17


关于这部分问题:



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



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



  1. 您已将PHP升级到较新版本,该版本可能具有error_reporting,display_errors或其他相关设置的其他默认值。

  2. 您已删除或引入了某些代码(可能在依赖项中),这些代码在运行时使用ini_set()error_reporting()设置相关设置(在代码中搜索这些代码)

  3. 您更改了网络服务器配置(假设此处为apache):.htaccess文件和vhost配置也可以操作php设置。

  4. 通常不会显示/报告通知(请参阅PHP手册)
    因此有可能在设置服务器时,由于某种原因(文件权限??)无法加载php.ini文件,并且您处于默认设置。后来,bug已经解决(偶然),现在它可以加载正确的php.ini文件,并将error_reporting设置为显示通知。[156]


其它参考18


如果使用类,则需要确保使用$this引用成员变量:


class Person
{
    protected $firstName;
    protected $lastName;

    public function setFullName($first, $last)
    {
        // Correct
        $this->firstName = $first;

        // Incorrect
        $lastName = $last;

        // Incorrect
        $this->$lastName = $last;
    }
}

其它参考19


将抛出未定义索引通知的另一个原因是,数据库查询中省略了一列。


即:


$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上,事情都区分大小写。


请参阅堆栈上的以下Q& A's:



  • MySQL中的表名是否区分大小写?

  • 查询中的
  • mysql区分大小写的表名

  • MySql - 不同服务器中表格的区分大小写问题


其它参考20


使用三元组是简单,可读和干净的:[160]


Pre PHP 7

如果设置了另一个变量的值,则将变量分配给另一个变量的值,否则分配null(或者您需要的任何默认值):


$newVariable = isset($thePotentialData) ? $thePotentialData : null;


PHP 7 +

除了使用Null Coalescing Operator之外,它们相同。不再需要调用isset(),因为它是内置的,并且不需要提供变量来返回,因为它假定返回被检查变量的值:[161]


$newVariable = $thePotentialData ?? null;


两者都会停止OP问题中的通知,两者完全相同于:


if (isset($thePotentialData)) {
    $newVariable = $thePotentialData;
} else {
    $newVariable = null;
}


&NBSP;点击
如果你不需要设置一个新变量,那么你可以直接使用三元的返回值,例如echo,函数参数等:


回声:


echo 'Your name is: ' . isset($name) ? $name : 'You did not provide one';


功能


$foreName = getForeName(isset($userId) ? $userId : null);

function getForeName($userId)
{
    if ($userId === null) {
        // Etc
    }
}


上面的方法与数组相同,包括会话等,用例如:
替换正在检查的变量
$_SESSION['checkMe']结果
或者你需要多深层次,例如:

$clients['personal']['address']['postcode']





&NBSP;


抑制


可以使用@抑制PHP通知或降低错误报告级别,但不能解决问题,它只是停止在错误日志中报告。这意味着您的代码仍然尝试使用未设置的变量,这可能会或可能不会意味着某些内容无法按预期工作 - 具体取决于缺失值的重要性。


你应该真正检查这个问题并适当地处理它,或者提供不同的消息,或者甚至只是为其他一切返回一个空值来识别精确的状态。


如果您只关心通知不在错误日志中,那么作为选项,您可以简单地忽略错误日志。

其它参考21


可能你使用旧的PHP版本,直到现在升级PHP,这是它工作的原因,直到现在多年来没有任何错误。
直到PHP4,如果您在没有定义变量的情况下使用变量,则没有错误,但从PHP5开始,它会为所讨论的代码抛出错误。

其它参考22


处理文件时,需要使用正确的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>";

?>


参考:



  • http://php.net/manual/en/features.file-upload.post-method.php


其它参考23


提交HTML表单后变量不存在的一个常见原因是表单元素未包含在<form>标记中:[162]


示例:Ele不包含在<form>


<form action="example.php" method="post">
    <p>
        <input type="text" name="name" />
        <input type="submit" value="Submit" />
    </p>
</form>

<select name="choice">
    <option value="choice1">choice 1</option>
    <option value="choice2">choice 2</option>
    <option value="choice3">choice 3</option>
    <option value="choice4">choice 4</option>
</select>


示例:元素现在包含在<form>


<form action="example.php" method="post">
    <select name="choice">
        <option value="choice1">choice 1</option>
        <option value="choice2">choice 2</option>
        <option value="choice3">choice 3</option>
        <option value="choice4">choice 4</option>
    </select>
    <p>
        <input type="text" name="name" />
        <input type="submit" value="Submit" />
    </p>
</form>

其它参考24


这些通知是因为你没有使用变量definedmy_index键不存在于$my_array变量中。


这些通知每次都被触发,因为你code不正确,但可能你没有报告通知。


解决错误:


$my_variable_name = "Variable name"; // defining variable
echo "My variable value is: " . $my_variable_name;

if(isset($my_array["my_index"])){
    echo "My index value is: " . $my_array["my_index"]; // check if my_index is set 
}


解决这个问题的另一种方法:


ini_set("error_reporting", false)

其它参考25


在PHP中,您需要先定义变量,然后才能使用它
我们可以非常有效地检查变量是否定义!


//If you only want to check variable has value and value has true and false value.
//But variable must be defined first.

if($my_variable_name){

}

//If you want to check variable is define or undefine
//Isset() does not check that variable has true or false value
//But it check null value of variable
if(isset($my_variable_name)){

}


简单说明


//It will work with :- true,false,NULL
$defineVarialbe = false;
if($defineVarialbe){
    echo "true";
}else{
    echo "false";
}

//It will check variable is define or not and variable has null value.
if(isset($unDefineVarialbe)){
    echo "true";
}else{
    echo "false";
}