Прошу подсказать по учебной задаче.
Требуется модифицировать класс Accessor таким образом, чтобы его объекты можно было сериализовать при помощи serialize() и восстановить при помощи unserialize(). По возможности организовать сериализацию таким образом, чтобы объект сохранялся в JSON-формате.
require_once 'include.php';
$obj = new Accessor();
print_r($obj->jsonSerialize());
Файл include.php:
class Accessor implements JsonSerializable
{
private $array = ['key1' =>'1','key2' =>'2','key7' =>'7'];
private $go = 123321;
public function __construct(array $array) {
$this->array = $array;
}
public function jsonSerialize() {
return $this->array;
}
}
Почему jsonSerialize() не отрабатывает?
Давайте внесем некоторую ясность ваш вопрос. Сначала вы пишите про функции стандартной сериализации в пхп - serialize()/unserialize(). Они сохраняют переменную в строку в своем неком формате.
Пример:
class Accessor {
private $data = [
'key1' => 'value1',
'key2' => 2,
];
private $val = 100;
}
$a = new Accessor();
print serialize( $a );
на выходе получим строку следующего формата (она не совсем корректна, т.к. содержит непечатные символы, которые сюда не копируются)
O:8:"Accessor":2:{s:14:"O:8:"Accessor":2:{s:14:"Accessordata";a:2:{s:4:"key1";s:6:"value1";s:4:"key2";i:2;}s:13:"Accessorval";i:100;}
Данный метод сохранения весьма широко использовался лет так 10 назад, до начала массового использования JSON. Одно из его преимуществ относительно JSON в том, что он содержит информацию о типах. В самом начале идет строка O:8:"Accessor" (O-объект, 8 - длина имени класса, далее название класса). Поэтому с помощью метода unserialize вы получите экземпляр этого же класса.
Недостатком относительно JSON является тот факт, что этот формат не переносим между другими языками. Это внутренний формат для пхп.
А вот JSON напротив, является форматом обмена данных между разными системами но при этом сам по себе не содержит сведений о используемых типах данных.
Эти методы сериализации при вызовах используют "магические" методы объектов __sleep() и __wakeup(), при их наличии в классе объекта, либо если класс поддерживает интерфейс Serializable.
Данный функционал позволяет получить данные объекта, которые следует сериализовать (чтобы не записывать объект целиком), а также выполнить действия по восстановлению состояния после того как объект десериализован.
Далее про кодирование в JSON. Для этих целей используются функции json_encode()/json_decode(). private поля класс не сериализуются. В случае приведенного выше класса, код
print json_encode( $a );
вернeт "пустой объект" - строку {}. Если же поля будут объявлены как public, то объект будет сериализован в следующую JSON-строку:
{"data":{"key1":"value1","key2":2},"val":100}
Теперь в вашем коде использован интерфейс JsonSerializable. Как и в случаях с serialize() и методами __sleep() и Serializable::serialize этот инетерфейс позволяет получить данные объекта, которые должны быть сохранены. Когда вы хотите сериализовать объект вы все так же вызываете json_encode($a), если объект не поддерживает указанный интерфейс, то происходит сериализация всех доступных полей. Если же переданный объект его поддерживает, то будет вызван метод jsonSerialize() и сериализованы будут только те данные, которые он вернет.
Это позволяет во-первых сериализовать не все подряд, а только нужное, во-вторых - позволяет сериализовать любые поля, которые мы сочтем нужным, поскольку сами формируем массив значений (то есть вручную сохраняем, например, приватные поля).
Поэтому вернув в класс private поля и добавив данный интерфейс:
class Accessor implements JsonSerializable {
private $data = [
'key1' => 'value1',
'key2' => 2,
];
private $val = 100;
public function jsonSerialize(){
return $this->data;
}
}
вызов json_encode($a) вернет нам только значения массива data:
{"key1":"value1","key2":2}
Если нам требуется сохранить значения и $dataи $val, то мы определяем метод соответствующим образом:
public function jsonSerialize(){
return ['data' => $this->data, 'val' => $this->val];
}
В общем, тут надо понять, что сам метод jsonSerialize ничего не кодирует, а просто предоставляет данные, которые должны быть закодированы.
И возвращаясь в вашему вопросу. Невозможно сказать, как следует модифицировать класс, который указан в задании, поскольку я так понимаю это не его первоначальный вид. Во вторых инструменты serialize() и формат JSON в принципе никак не связаны в пхп. Нельзя добиться, чтобы serialize вдруг вернул json-строку,он возвращает свой формат. Но для этого можно использовать другие инструменты, такие как json_encode.
В зависимости от того, что вы хотите сделать.
Если нужно, чтобы возвращался сериализованный массив из свойства array при вызове метода jsonSerialize(), то пропишите в нем:
return json_encode($this->array);
То же самое сделайте для unserialize, только json_decode.
Если же вы хотите, чтобы все работало при вызове именно функции php serialize, то так, увы, не получится, ввиду того, что метод встроенный и алгоритм его работы уже определен.
Есть способ переопределить этот метод через C в движке php. Но я не думаю, что в этом состоит задача.
Продвижение своими сайтами как стратегия роста и независимости