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

2022-08-30 15:17:21

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

Array
(
    [207] => sdf
    [210] => sdf
)

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

print_r($output); 
echo $output[207];   // Undefined Offset
echo $output["207"]; // Undefined Offset

该数组是对array_diff_key的调用的结果,最初是通过 HTTP POST 请求以 JSON 形式输入的。$output

array_keys给了我以下几点:

Array
(
   [0] => 207
   [1] => 210
)

针对评论:

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

   string(3) "207"

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

   bool(false)

答案 1

请参阅 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"
// }

print_r这两个数组上给出相同的输出,但使用var_dump您可以看到差异。

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

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

print_r($output);
echo $output[207];
echo $output["207"];

简单的解决方法是将可选参数传递给json_decode,以指定您想要数组而不是对象:trueassoc

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

print_r($output);
echo $output[207];
echo $output["207"];

答案 2

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

如果您有此对象:

object(stdClass)#1 (2) {
  ["207"]=>
  string(3) "sdf"
  ["210"]=>
  string(3) "sdf"
}

你用它铸造

$array = (array)$object

你得到这个数组

array(2) {
  ["207"]=>
  string(3) "sdf"
  ["210"]=>
  string(3) "sdf"
}

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

由于您正在将像上面这样的对象应用于字符串json_decode()

$json = '{"207":"sdf", "210":"sdf"}'

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

$json = '[{"numAttr":207, "strAttr":"sdf"}, {"numAttr":210, "strAttr":"sdf"}]'

与现在的数据结构相比,此数据结构有几个优点:

  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);

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

$map = json_decode($json, true);

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

array(2) {
  [207]=>
  string(3) "sdf"
  [210]=>
  string(3) "sdf"
}

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

不过,我认为更改JSON数据结构是一个更干净的解决方案,尽管我知道这样做可能是不可能的。