PHP / json_encode:处理具有数字属性的混合数组和对象

时间:2018-10-06 00:28:52

标签: php json associative-array

我最近不得不解决旧版PHP应用程序中的错误。此应用程序从另一个应用程序接收带有JSON格式的请求:

{
  "someList": [
    "item A",
    "item B"
  ],
  "ratings": {
    "0": 0.001234,
    "1": 0.0666,
    "2": 0.09876,
    "3": 0.777777
  }
}

当将其反序列化为本地PHP“关联数组”时,列表和映射(键0、1、2和3)都看起来像列表。很好,我可以解决这个问题。但是,此应用程序会对此数据进行计算,并在以大致相同的格式序列化回JSON之前将其添加到数据中,然后再将其发送到另一个应用程序。这就是问题所在。上面的json_encode($data)的开箱即用结果为:

{
  "someList": [
    "item A",
    "item B"
  ],
  "ratings": [
    0.001234,
    0.0666,
    0.09876,
    0.777777
  ]
}

我的钥匙都没了...

我看到我可以JSON_FORCE_OBJECT使用echo json_encode($data, JSON_FORCE_OBJECT),但是我得到了:

{
  "someList": {
    "0": "item A",
    "1": "item B"
  },
  "ratings": {
    "0": 0.001234,
    "1": 0.0666,
    "2": 0.09876,
    "3": 0.777777
  }
}

现在我在第一个列表中有键,我不想。 是否可以序列化此JSON,使得someList将成为列表(无键),而ratings将成为地图/对象(具有键0、1、2和3) ?

4 个答案:

答案 0 :(得分:3)

当在数组列表上调用json_encode时,数字相关索引从0开始,PHP会将列表视为索引数组,而不是关联数组。要强制php将其视为关联数组,可以在调用json_encode之前将数组强制转换为对象。

示例:

$somelist = ["item A", "item B"];
$ratings = [0.001234, 0.666, 0.09876, 0.777777];
$final = ['someList' => $somelist, 'ratings' => (object) $ratings];

echo json_encode($final);

输出:

{["item A","item B"],{"0":0.001234,"1":0.666,"2":0.09876,"3":0.777777}}

答案 1 :(得分:3)

我也一直在努力尝试在同一响应中返回带有常规数组和带有数字键的对象的JSON。

我发现的一个解决方案是,您可以构建一个stdObject并使用$obj->{'0'}定义密钥。

这是一个完整的例子:


$decoded = json_decode('{
  "someList": [
    "item A",
    "item B"
  ],
  "ratings": {
    "0": 0.001234,
    "1": 0.0666,
    "2": 0.09876,
    "3": 0.777777
  }
}', true);

// Do stuff with $decoded['ratings']

$ratings = new \stdClass;
foreach ($decoded['ratings'] as $key => $rating) {
    $ratings->{$key} = $rating;
}

echo json_encode([
    'someList' => $decoded['someList'],
    'ratings' => $ratings
]);

然后将输出以下内容:

{
  "someList": [
    "item A",
    "item B"
  ],
  "ratings": {
    "0": 0.001234,
    "1": 0.0666,
    "2": 0.09876,
    "3": 0.777777
  }
}

答案 2 :(得分:1)

我通常不会建议手动“构建” JSON,但是将有效JSON的位级联应该是相当安全的,而且我认为这是使它起作用的唯一方法。

$somelist = ["item A", "item B"];
$ratings = [0.001234, 0.666, 0.09876, 0.777777];

$json = sprintf(
    '{"somelist":%s,"ratings":%s}',
    json_encode($somelist),
    json_encode($ratings, JSON_FORCE_OBJECT)
);
echo $json;

或者如果您要使用更大的对象,则可以遍历数据以编程方式进行操作。

$original_json = '{"someList":["item A","item B"],"ratings""{"0":0.001234,"1":0.0666,"2":0.09876,"3":0.777777}}';
$data = json_decode($original_json);
// do whatever you need to do with the data
array_walk($data->someList, function(&$v, $k){$v .= " is changed";});

$vsprintf_args = [];
$format_str = "{";
foreach($data as $k=>$v) {
    $format_str .= '%s:%s,';
    $vsprintf_args[] = json_encode($k);
    $vsprintf_args[] = json_encode($v, ($k === "ratings" ? JSON_FORCE_OBJECT : 0));
}
$format_str = trim($format_str, ",") . "}";
$json = vsprintf($format_str, $vsprintf_args);
echo $json;

输出:

{"somelist":["item A","item B"],"ratings":{"0":0.001234,"1":0.666,"2":0.09876,"3":0.777777}}

答案 3 :(得分:0)

通过stdClass解码原始JSON时,可以使用json_decode($json, false);而不是关联数组来找到解决方案。然后,json_encode生成的stdClass密钥将被保留。

这是一个完整的例子:

<?php

$json = <<<JSON
{
  "someList": [
    "item A",
    "item B"
  ],
  "ratings": {
    "0": 0.001234,
    "1": 0.0666,
    "2": 0.09876,
    "3": 0.777777
  }
}
JSON;

// Passing false for the second param (or omitting it)
// returns a stdClass instead of associative array
$data = json_decode($json, false);

echo json_encode($data, JSON_PRETTY_PRINT);

哪个输出:

{
    "someList": [
        "item A",
        "item B"
    ],
    "ratings": {
        "0": 0.001234,
        "1": 0.0666,
        "2": 0.09876,
        "3": 0.777777
    }
}