PHP / json_encode: работа со смешанными массивами и объектами с числовыми свойствами - PullRequest
0 голосов
/ 06 октября 2018

Мне недавно пришлось устранять ошибку в устаревшем 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 a la 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)?

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

удалось найти решение, используя 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
    }
}
0 голосов
/ 06 октября 2018

Обычно я бы не советовал "создавать" 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}}
...