Сериализация в BSON

Массивы

Если массив представляет собой упакованный массив — то есть пустой массив или ключи начинаются с 0 и идут последовательно без пробелов: BSON-массив.

Если массив не упакован — то есть содержит ассоциативные (строковые) ключи, ключи не начинаются с 0 или содержат пробелы: BSON-объект

Документ верхнего уровня (корневой) всегда сериализуется как BSON-документ.

Примеры

Эти PHP-массивы сериализуются как BSON-массив:

[8, 5, 2, 3] => [8, 5, 2, 3]
[0 => 4, 1 => 9] => [4, 9]

Эти PHP-массивы сериализуются как BSON-документ:

[0 => 1, 2 => 8, 3 => 12] => {"0": 1, "2": 8, "3": 12}
["foo" => 42] => {"foo": 42}
[1 => 9, 0 => 10] => {"1": 9, "0": 10}

Обратите внимание, что пять приведённых примеров — выдержки из полного документа и представляют только одно значение внутри документа.

Объекты

Если объект принадлежит типу stdClass, он сериализуется как BSON-документ.

Если объект — поддерживаемый класс, который реализует интерфейс MongoDB\BSON\Type, используется логика сериализации BSON для этого конкретного типа. Экземпляры с типом MongoDB\BSON\Type (исключая тип MongoDB\BSON\Serializable) можно сериализовать только как значение поля документа. Попытка сериализовать такой объект как корневой документ выбросит исключение MongoDB\Driver\Exception\UnexpectedValueException.

Если объект принадлежит неизвестному классу, который реализует интерфейс MongoDB\BSON\Type, выбрасывается исключение MongoDB\Driver\Exception\UnexpectedValueException.

Если объект принадлежит какому-либо другому классу без реализации какого-либо специального интерфейса, он сериализуется как BSON-документ. Остаются только открытые (public) свойства, а защищённые (protected) и закрытые (private) свойства игнорируются.

Если объект принадлежит к классу, который реализует интерфейс MongoDB\BSON\Serializable, вызывают метод MongoDB\BSON\Serializable::bsonSerialize() и сериализуют массив или stdClass, которые возвращает метод, как BSON-документ или как BSON-массив. Тип BSON определят следующие условия:

  1. Корневые документы требуется сериализовать как BSON-документ.

  2. Объекты с типом MongoDB\BSON\Persistable требуется сериализовать как BSON-документы.

  3. Если метод MongoDB\BSON\Serializable::bsonSerialize() возвращает упакованный массив, его сериализуют как BSON-массив.

  4. Если метод MongoDB\BSON\Serializable::bsonSerialize() возвращает неупакованный массив или объект stdClass, его сериализуют как BSON-документ.

  5. Если метод MongoDB\BSON\Serializable::bsonSerialize() не вернул массив или объект stdClass, выбрасывается исключение MongoDB\Driver\Exception\UnexpectedValueException.

Если объект принадлежит классу, который реализует интерфейс MongoDB\BSON\Persistable (что подразумевает реализацию метода MongoDB\BSON\Serializable), свойства остаются по аналогии с предыдущими абзацами, но также добавляется дополнительное свойство __pclass в виде Binary-значения с подтипом 0x80 и данными, которые содержат полное имя класса объекта, который сериализуется.

Свойство __pclass добавляется в массив или объект, который возвращает метод MongoDB\BSON\Serializable::bsonSerialize(), что означает, что оно перезапишет любой ключ или свойство __pclass в значении, которое возвращает метод MongoDB\BSON\Serializable::bsonSerialize(). Если требуется избежать такого поведения и установить собственное значение __pclass, вместо реализации интерфейса MongoDB\BSON\Persistable следует напрямую реализовать интерфейс MongoDB\BSON\Serializable.

Примеры

<?php

class stdClass
{
public
$foo = 42;
}
// => {"foo": 42}

class MyClass
{
public
$foo = 42;
protected
$prot = 'вино';
private
$fpr = 'сыр';
}
// => {"foo": 42}

class AnotherClass1 implements MongoDB\BSON\Serializable
{
public
$foo = 42;
protected
$prot = 'вино';
private
$fpr = 'сыр';

public function
bsonSerialize(): array
{
return [
'foo' => $this->foo, 'prot' => $this->prot];
}
}
// => {"foo": 42, "prot": "вино"}

class AnotherClass2 implements MongoDB\BSON\Serializable
{
public
$foo = 42;

public function
bsonSerialize(): self
{
return
$this;
}
}
// => MongoDB\Driver\Exception\UnexpectedValueException("bsonSerialize() did not return an array or stdClass")

class AnotherClass3 implements MongoDB\BSON\Serializable
{
private
$elements = ['foo', 'bar'];

public function
bsonSerialize(): array
{
return
$this->elements;
}
}
// => {"0": "foo", "1": "bar"}

/**
* Вложенные сериализуемые классы
*/

class AnotherClass4 implements MongoDB\BSON\Serializable
{
private
$elements = [0 => 'foo', 2 => 'bar'];

public function
bsonSerialize(): array
{
return
$this->elements;
}
}
// => {"0": "foo", "2": "bar"}

class ContainerClass1 implements MongoDB\BSON\Serializable
{
public
$things;

public function
__construct()
{
$this->things = new AnotherClass4();
}

function
bsonSerialize(): array
{
return [
'things' => $this->things];
}
}
// => {"things": {"0": "foo", "2": "bar"}}


class AnotherClass5 implements MongoDB\BSON\Serializable
{
private
$elements = [0 => 'foo', 2 => 'bar'];

public function
bsonSerialize(): array
{
return
array_values($this->elements);
}
}
// => {"0": "foo", "1": "bar"} as a root class
["foo", "bar"] as a nested value

class ContainerClass2 implements MongoDB\BSON\Serializable
{
public
$things;

public function
__construct()
{
$this->things = new AnotherClass5();
}

public function
bsonSerialize(): array
{
return [
'things' => $this->things];
}
}
// => {"things": ["foo", "bar"]}


class AnotherClass6 implements MongoDB\BSON\Serializable
{
private
$elements = ['foo', 'bar'];

function
bsonSerialize(): object
{
return (object)
$this->elements;
}
}
// => {"0": "foo", "1": "bar"}

class ContainerClass3 implements MongoDB\BSON\Serializable
{
public
$things;

public function
__construct()
{
$this->things = new AnotherClass6();
}

public function
bsonSerialize(): array
{
return [
'things' => $this->things];
}
}
// => {"things": {"0": "foo", "1": "bar"}}

class UpperClass implements MongoDB\BSON\Persistable
{
public
$foo = 42;
protected
$prot = 'вино';
private
$fpr = 'сыр';

private
$data;

public function
bsonUnserialize(array $data): void
{
$this->data = $data;
}

public function
bsonSerialize(): array
{
return [
'foo' => $this->foo, 'prot' => $this->prot];
}
}
// => {"foo": 42, "prot": "вино", "__pclass": {"$type": "80", "$binary": "VXBwZXJDbGFzcw=="}}

?>