Сериализовать/unserialize PHP-объект-график для JSON
Я хотел сериализовать полный PHP-объект-граф для строкового представления JSON и неэтериализовать его на идентичный PHP-объект-граф.
Вот резюме вариантов, которые я рассмотрел, и причины, по которым они не работают для меня:
-
serialize()
не выполняет то, что я хочу, потому что он использует формат, специфичный для PHP. Я хочу формат, который широко поддерживается большинством языков и доступен для чтения/редактирования.
-
json_encode()
не делает то, что я хочу, потому что он просто делает простые значения и массивы, а не объекты. (Я фактически использую это в своей реализации, см. Ниже.)
-
var_export()
не обрабатывает циклические ссылки и не выполняет то, что я хочу (см. выше.) (обратите внимание, что моя текущая реализация также не обрабатывает круговые ссылки - см. комментарии и ответ ниже для пояснения этот вопрос.)
-
Себастьян Бергманн Объект Freezer - хорошая реализация, но он не делает то, что я хочу - он использует очень длинный формы и полагается на заполнение сериализованных объектов с помощью GUID.
-
Serialized не делает то, что я хочу - он фактически не выполняет сериализацию, он анализирует вывод serialize()
и создает другое представление, например XML, но не может проанализировать это представление. (он также не поддерживает JSON - XML - очень длинная форма, и я не хочу этого).
Теперь у меня есть рабочая реализация для совместного использования:
https://github.com/mindplay-dk/jsonfreeze
JSON-представление объектного графа выглядит следующим образом:
{
"#type": "Order",
"orderNo": 123,
"lines": [{
"#type": "OrderLine",
"item": "milk \"fuzz\"",
"amount": 3,
"options": null
}, {
"#type": "OrderLine",
"item": "cookies",
"amount": 7,
"options": {
"#type": "#hash",
"flavor": "chocolate",
"weight": "1\/2 lb"
}
}],
"paid": true
}
Этот подход предназначен для работы с агрегатом чистой древовидной структуры - не допускаются циклические ссылки, а также несколько ссылок на одни и те же объекты. Другими словами, это не универсальное назначение, например, serialize()
и unserialize()
, которые функционируют для любого PHP-объекта-графика.
В моем начальном подходе Я использовал сериализованную форму, которая была по существу базовым списком объектов. Первым объектом в списке (число 0) является корень сериализованного объектного графа, любые другие объекты хранятся в том порядке, в котором они найдены.
В текущей реализации представление JSON похоже на исходную древовидную структуру до такой степени, что это возможно, что позволяет фактически работать с представлением JSON объектного графа в JavaScript. Единственное отклонение - это свойство magic #type
(с префиксом # для предотвращения столкновения с именами свойств) и #hash
"type", используемое для выделения хешей array
-типов (хранимых как объекты JSON) из регулярного array
-типы (хранятся как массивы JSON).
Я оставляю эти заметки о предыдущей версии здесь для исторических целей.
Циклические ссылки обрабатываются просто, никогда не сохраняя вложенные объекты внутри сериализованного представления каждого объекта - вместо этого любая объектная ссылка сохраняется как объект JSON с индексом объекта - например. {"__oref":2}
является ссылкой на объект с индексом 2
в списке объектов.
У меня проблема с ссылками на массивы в моей реализации - когда я var_dump() внутри кода, который восстанавливает ссылки на объекты в массиве, они заполняются, но в какой-то момент массив копируется, и вы закончите с пустой копией. Я попытался помещать символы &
всюду в коде, но независимо от того, где я передаю по ссылке, конечным результатом является пустой массив.
Ответы
Ответ 1
Готовое script (опубликовано выше) соответствует моим точным требованиям:
-
Сериализуйте и несериализуйте весь агрегат.
-
Имейте представление JSON, которое близко напоминает исходную структуру данных.
-
Не загрязняйте структуру данных динамически сгенерированными ключами или другими данными.
Он не обрабатывает циклические ссылки. Как указано в комментарии выше, нет правильного способа хранения круговых ссылок или нескольких ссылок на один и тот же объект, так как все они равны. Понимая это, я решил, что мой объектный граф должен быть обычным деревом и принял это ограничение как "хорошую вещь".
update: теперь ouput может быть отформатирован с отступом, новыми символами и пробелами - для меня было важно иметь удобное для чтения (и удобное для источника) представление для моих целей. (Форматирование может быть включено или отключено по мере необходимости.)
Ответ 2
Я не знаю, если это то, что вам нужно, но если вы заинтересованы только в получении публичных свойств объекта, get_object_vars ($ obj) выполнит трюк.
<?php
class foo {
public $fname = "John";
public $sname = "Doe";
private $status = null;
static $type = "person";
}
$obj = new foo;
print_r( (get_object_vars($obj)) );
print json_encode(get_object_vars($obj));
?>
Будет выводиться:
Массив ([fname] = > John [sname] = > Doe)
{ "имя_файла": "Джон", "SNAME": "Doe" }
Вышеупомянутый метод бесполезен для доступа к ссылкам функций и частным переменным, но вы можете использовать его в сочетании с некоторым другим кодом, чтобы сбить то, что вам нужно.
Динеш.