访问存在的数组元素时未定义的偏移量

Kev*_*ave 29 php arrays indexing element undefined

我有一个数组和PHP,当我打印出来时,我可以看到我需要访问的值,但是当我尝试通过他们的密钥访问它时,我得到一个PHP通知.我用print_r打印了数组:

Array
(
    [207] => sdf
    [210] => sdf
)
Run Code Online (Sandbox Code Playgroud)

当我尝试使用索引访问数组时,我得到一个未定义的偏移通知.这是我的代码:

print_r($output); 
echo $output[207];   // Undefined Offset
echo $output["207"]; // Undefined Offset
Run Code Online (Sandbox Code Playgroud)

$output数组是对array_diff_key的调用的结果,最初通过HTTP POST请求作为JSON输入.

array_keys给了我以下内容:

Array
(
   [0] => 207
   [1] => 210
)
Run Code Online (Sandbox Code Playgroud)

回应评论:

var_dump(key($output)); 输出:

   string(3) "207"
Run Code Online (Sandbox Code Playgroud)

var_dump(isset($output[key($output)])); 输出:

   bool(false)
Run Code Online (Sandbox Code Playgroud)

Pau*_*aul 25

请参阅PHP手册中有关将对象转换为数组的内容:

键是成员变量名,有一些值得注意的例外:整数属性是不可访问的 ; 私有变量的类名前置于变量名; 受保护的变量在变量名前面加上'*'.

从PHP中的对象转换为数组时,整数数组键在内部存储为字符串.当您在PHP中访问数组元素或正常使用数组时,包含有效整数的键将自动转换为整数.内部存储为字符串的整数是不可访问的密钥.

注意区别:

$x = (array)json_decode('{"207":"test"}');
var_dump(key($x));  // string(3) "207"

var_dump($x);
// array(1) {
//   ["207"]=>
//   string(4) "test"
// }


$y['207'] = 'test';
var_dump(key($y));  // int(207)

var_dump($y);
// array(1) {
//   [207]=>
//   string(4) "test"
// }
Run Code Online (Sandbox Code Playgroud)

这两个数组上的print_r提供相同的输出,但使用var_dump可以看到差异.

以下是一些可以重现您确切问题的代码:

$output = (array)json_decode('{"207":"sdf","210":"sdf"}');

print_r($output);
echo $output[207];
echo $output["207"];
Run Code Online (Sandbox Code Playgroud)

而简单的解决方法是传递truejson_decode为可选assoc参数,指定你想要的数组不是一个对象:

$output = json_decode('{"207":"sdf","210":"sdf"}', true);

print_r($output);
echo $output[207];
echo $output["207"];
Run Code Online (Sandbox Code Playgroud)


Wal*_*oss 20

转换array具有有效整数的字符串键的对象时,会出现问题.

如果你有这个对象:

object(stdClass)#1 (2) {
  ["207"]=>
  string(3) "sdf"
  ["210"]=>
  string(3) "sdf"
}
Run Code Online (Sandbox Code Playgroud)

然后你把它投了

$array = (array)$object
Run Code Online (Sandbox Code Playgroud)

你得到这个数组

array(2) {
  ["207"]=>
  string(3) "sdf"
  ["210"]=>
  string(3) "sdf"
}
Run Code Online (Sandbox Code Playgroud)

它具有只能通过循环访问的密钥,因为直接访问$array["207"]将始终转换$array[207]不存在的密钥.

因为您正在将类似上面的对象json_decode()应用于类似的字符串

$json = '{"207":"sdf", "210":"sdf"}'
Run Code Online (Sandbox Code Playgroud)

最好的解决方案是首先避免使用数字键.这些可能更好地建模为对象数组的数字属性:

$json = '[{"numAttr":207, "strAttr":"sdf"}, {"numAttr":210, "strAttr":"sdf"}]'
Run Code Online (Sandbox Code Playgroud)

这种数据结构比现在有几个优点:

  1. 它更好地反映原始数据,作为具有数字属性的对象的集合
  2. 它很容易与其他属性扩展
  3. 它在不同系统中更容易移植(如您所见,您当前的数据结构导致PHP出现问题,但如果您碰巧使用其他语言,则可能很容易遇到类似问题).

如果需要属性→对象映射,则可以快速获取它,例如,如下所示:

function getNumAttr($obj) { return $obj->numAttr; } // for backward compatibility
$arr = json_decode($json); // where $json = '[{"numAttr":...
$map = array_combine(array_map('getNumAttr', $arr), $arr);
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是ascii-lime建议:强制json_decode()输出关联数组而不是对象,方法是将其第二个参数设置为true:

$map = json_decode($json, true);
Run Code Online (Sandbox Code Playgroud)

对于您的输入数据,这直接产生

array(2) {
  [207]=>
  string(3) "sdf"
  [210]=>
  string(3) "sdf"
}
Run Code Online (Sandbox Code Playgroud)

请注意,数组的键现在是整数而不是字符串.

我会考虑将JSON数据结构更改为更清晰的解决方案,尽管我知道可能无法这样做.


Pau*_*aul 1

我刚刚发现这个错误,当通过调用unserialize创建数组时,该错误有时会导致 PHP 中的数组元素无法访问。

创建一个包含(或从命令行运行)以下脚本的测试 PHP 文件:

<?php 

$a = unserialize('a:2:{s:2:"10";i:1;s:2:"01";i:2;}'); 

print $a['10']."\n";

$a['10'] = 3; 
$a['01'] = 4; 

print_r($a);

foreach ($a as $k => $v) 
{ 
  print 'KEY: '; 
  var_dump($k); 
  print 'VAL: '; 
  var_dump($v); 
  print "\n"; 
}
Run Code Online (Sandbox Code Playgroud)

如果出现错误,则表明您的 PHP 版本存在此错误,我建议升级到 PHP 5.3