PHP 8.3.21 Released!

Serialización y deserialización de variables PHP en MongoDB

Este documento explica cómo se convierten las estructuras compuestas (es decir, los documentos, los arrays y los objetos) entre los valores BSON y PHP.

Serialización en BSON

Arrays

Si un array es un array compacto — es decir, un array vacío o las claves comienzan en 0 y son secuenciales sin huecos : array BSON.

Si el array no es compacto — es decir, que tiene claves asociativas (cadenas), que las claves no comienzan en 0, o que hay huecos : objeto BSON.

Un documento de nivel superior (raíz), siempre serializado como documento BSON.

Ejemplos

Estos ejemplos se serializan como array BSON :

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

Estos ejemplos se serializan como objeto 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 }

Es de notar que los cinco ejemplos son extractos de un documento completo, y solo representan un valor dentro de un documento.

Objetos

Si un objeto es de la clase stdClass, serializar como documento BSON.

Si un objeto es una clase soportada que implementa MongoDB\BSON\Type, entonces utilizar la lógica de serialización BSON para este tipo específico. Las instancias de MongoDB\BSON\Type (a excepción de MongoDB\BSON\Serializable) solo pueden ser serializadas como valor de campo de documento. Intentar serializar tal objeto como documento raíz lanzará una MongoDB\Driver\Exception\UnexpectedValueException.

Si un objeto es de una clase desconocida que implementa la interfaz MongoDB\BSON\Type, entonces se lanza una MongoDB\Driver\Exception\UnexpectedValueException.

Si un objeto es de otra clase, sin implementar una interfaz especial, serializar como documento BSON. Mantener solo las propiedades públicas, e ignorar las propiedades protegidas y privadas.

Si un objeto es de una clase que implementa MongoDB\BSON\Serializable, llamar MongoDB\BSON\Serializable::bsonSerialize() y utilizar el array o stdClass devuelto para serializar como documento BSON o array. El tipo BSON será determinado por las siguientes reglas :

  1. Los documentos raíz deben ser serializados como documento BSON.

  2. Los objetos MongoDB\BSON\Persistable deben ser serializados como documento BSON.

  3. Si MongoDB\BSON\Serializable::bsonSerialize() devuelve un array compacto, serializar como array BSON.

  4. Si MongoDB\BSON\Serializable::bsonSerialize() devuelve un array no compacto o stdClass, serializar como objeto BSON.

  5. Si MongoDB\BSON\Serializable::bsonSerialize() no devuelve un array o stdClass, lanzar una excepción MongoDB\Driver\Exception\UnexpectedValueException.

Si un objeto es de una clase que implementa la interfaz MongoDB\BSON\Persistable (lo que implica MongoDB\BSON\Serializable), obtener las propiedades de manera similar a los párrafos anteriores, pero también añadir una propiedad __pclass como valor binario, con un subtipo 0x80 y datos que llevan el nombre de la clase completamente calificado del objeto que se serializa.

La propiedad __pclass se añade al array o al objeto devuelto por MongoDB\BSON\Serializable::bsonSerialize(), lo que significa que sobrescribirá cualquier clave/propiedad __pclass en el valor de retorno de MongoDB\BSON\Serializable::bsonSerialize(). Si se desea evitar este comportamiento y definir su propio valor __pclass, no se debe implementar MongoDB\BSON\Persistable y se debería implementar MongoDB\BSON\Serializable directamente.

Ejemplos

<?php

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

class MyClass
{
public
$foo = 42;
protected
$prot = 'wine';
private
$fpr = 'cheese';
}
// => {"foo": 42}

class AnotherClass1 implements MongoDB\BSON\Serializable
{
public
$foo = 42;
protected
$prot = 'wine';
private
$fpr = 'cheese';

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

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"}

/**
* Nesting Serializable classes
*/

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"} como clase raíz
// ["foo", "bar"] como valor anidado

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 = 'wine';
private
$fpr = 'cheese';

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": "wine", "__pclass": {"$type": "80", "$binary": "VXBwZXJDbGFzcw=="}}

?>

Deserialización desde BSON

Advertencia

BSON documents can technically contain duplicate keys because documents are stored as a list of key-value pairs; however, applications should refrain from generating documents with duplicate keys as server and driver behavior may be undefined. Since PHP objects and arrays cannot have duplicate keys, data could also be lost when decoding a BSON document with duplicate keys.

La extensión mongodb deserializa los documentos BSON y los arrays BSON como arrays PHP. Aunque los arrays PHP son prácticos de usar, este comportamiento era problemático ya que diferentes tipos BSON podían ser deserializados en el mismo valor PHP (por ejemplo {"0": "foo"} y ["foo"]) y hacía imposible inferir el tipo BSON original. Por defecto, la extensión mongodb aborda esta preocupación asegurándose de que los arrays BSON y los documentos BSON se conviertan en arrays y objetos PHP, respectivamente.

Para los tipos compuestos, existen tres tipos de datos :

raíz

se refiere a un documento BSON de nivel superior solo

documento

se refiere a documentos BSON anidados solo

array

se refiere a un array BSON

Además de los tres tipos colectivos, también es posible configurar campos específicos en su documento para mapear los tipos de datos mencionados a continuación. Por ejemplo, el siguiente tipo de mapa le permite mapear cada documento incrustado en un array "addresses" a una clase Address y cada campo "city" en estos documentos de dirección incrustados a una clase City:

[
    'fieldPaths' => [
        'addresses.$' => 'MyProject\Address',
        'addresses.$.city' => 'MyProject\City',
    ],
]

Cada uno de estos tres tipos de datos, así como los mapeos específicos de los campos, pueden ser mapeados contra diferentes tipos PHP. Los valores de mapeo posibles son:

no definido o NULL (por defecto)

  • Un array BSON será deserializado en un array PHP.

  • Un documento BSON (raíz o anidado) sin propiedad __pclass [1] se convierte en un objeto stdClass, con cada clave de documento BSON definida como una propiedad de stdClass pública.

  • Un documento BSON (raíz o anidado) con una propiedad __pclass se convierte en un objeto PHP de la clase nombrada por la propiedad __pclass.

    Si la clase nombrada implementa la interfaz MongoDB\BSON\Persistable, entonces las propiedades del documento BSON, incluyendo la propiedad __pclass, se envían como array asociativo a la función MongoDB\BSON\Unserializable::bsonUnserialize() para inicializar las propiedades del objeto.

    Si la clase nombrada no existe o no implementa la interfaz MongoDB\BSON\Persistable, stdClass será utilizado y cada clave de documento BSON (incluyendo __pclass) será definida como una propiedad pública de stdClass.

    La funcionalidad __pclass se basa en el hecho de que la propiedad sea parte de un documento MongoDB recuperado. Si utiliza una » proyección al buscar documentos, debe incluir el campo __pclass en la proyección para que esta funcionalidad funcione.

"array"

Transforma un array BSON en un array PHP. No habrá tratamiento especial de una propiedad __pclass [1] pero puede ser definida como un elemento en el array devuelto si estaba presente en el documento BSON.

"object" o "stdClass"

Transforma un array BSON o un documento BSON en un objeto stdClass. No habrá tratamiento especial de una propiedad __pclass [1] pero puede ser definida como una propiedad pública en el objeto devuelto si estaba presente en el documento BSON.

"bson"

Transforma un array BSON en un MongoDB\BSON\PackedArray y un documento BSON en un MongoDB\BSON\Document, independientemente de si el documento BSON tiene una propiedad __pclass [1].

Nota: El valor bson solo está disponible para los tres tipos raíz, y no en los mapeos específicos de los campos.

todas las otras cadenas de caracteres

Define el nombre de la clase a la que el documento BSON debe ser deserializado. Para los documentos BSON que incluyen propiedades __pclass, esta clase tendrá prioridad.

Si la clase nombrada no existe o no implementa la interfaz MongoDB\BSON\Unserializable, se lanza una excepción MongoDB\Driver\Exception\InvalidArgumentException.

Si el objeto BSON tiene una propiedad __pclass y esta clase existe e implementa MongoDB\BSON\Persistable, tendrá prioridad sobre la clase proporcionada en el mapa de tipos.

Las propiedades del documento BSON, incluyendo la propiedad __pclass, serán enviadas como array asociativo a la función MongoDB\BSON\Unserializable::bsonUnserialize() para inicializar las propiedades del objeto.

TypeMaps

Los TypeMaps pueden ser definidos a través del método MongoDB\Driver\Cursor::setTypeMap() en un objeto MongoDB\Driver\Cursor, o el argumento $typeMap de MongoDB\BSON\toPHP(), MongoDB\BSON\Document::toPHP(), y MongoDB\BSON\PackedArray::toPHP(). Cada una de las tres clases (raíz, documento, y array) puede ser definida individualmente, además de los tipos específicos de los campos.

Si el valor en el TypeMap es NULL, esto significa lo mismo que el valor por defecto para este elemento.

Ejemplos

Estos ejemplos utilizan las siguientes clases:

MyClass

que no implementa ninguna interfaz

YourClass

que implementa MongoDB\BSON\Unserializable

OurClass

que implementa MongoDB\BSON\Persistable

TheirClass

que extiende OurClass

El método MongoDB\BSON\Unserializable::bsonUnserialize() de YourClass, OurClass, TheirClass itera sobre el array y define las propiedades sin modificaciones. También añade la propiedad $unserialized a true:

<?php

function bsonUnserialize( array $map )
{
foreach (
$map as $k => $value )
{
$this->$k = $value;
}
$this->unserialized = true;
}

/* typemap: [] (todos los valores por defecto) */
{ "foo": "yes", "bar" : false }
  -> stdClass { $foo => 'yes', $bar => false }

{ "foo": "no", "array" : [ 5, 6 ] }
  -> stdClass { $foo => 'no', $array => [ 5, 6 ] }

{ "foo": "no", "obj" : { "embedded" : 3.14 } }
  -> stdClass { $foo => 'no', $obj => stdClass { $embedded => 3.14 } }

{ "foo": "yes", "__pclass": "MyClass" }
  -> stdClass { $foo => 'yes', $__pclass => 'MyClass' }

{ "foo": "yes", "__pclass": { "$type" : "80", "$binary" : "MyClass" } }
  -> stdClass { $foo => 'yes', $__pclass => Binary(0x80, 'MyClass') }

{ "foo": "yes", "__pclass": { "$type" : "80", "$binary" : "YourClass") }
  -> stdClass { $foo => 'yes', $__pclass => Binary(0x80, 'YourClass') }

{ "foo": "yes", "__pclass": { "$type" : "80", "$binary" : "OurClass") }
  -> OurClass { $foo => 'yes', $__pclass => Binary(0x80, 'OurClass'), $unserialized => true }

{ "foo": "yes", "__pclass": { "$type" : "44", "$binary" : "YourClass") }
  -> stdClass { $foo => 'yes', $__pclass => Binary(0x44, 'YourClass') }

/* typemap: [ "root" => "MissingClass" ] */
{ "foo": "yes" }
  -> MongoDB\Driver\Exception\InvalidArgumentException("MissingClass does not exist")

/* typemap: [ "root" => "MyClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MyClass" } }
  -> MongoDB\Driver\Exception\InvalidArgumentException("MyClass does not implement Unserializable interface")

/* typemap: [ "root" => "MongoDB\BSON\Unserializable" ] */
{ "foo": "yes" }
  -> MongoDB\Driver\Exception\InvalidArgumentException("Unserializable is not a concrete class")

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MongoDB\BSON\Unserializable" } }
  -> YourClass { $foo => "yes", $__pclass => Binary(0x80, "MongoDB\BSON\Unserializable"), $unserialized => true }

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MyClass" } }
  -> YourClass { $foo => "yes", $__pclass => Binary(0x80, "MyClass"), $unserialized => true }

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "OurClass" } }
  -> OurClass { $foo => "yes", $__pclass => Binary(0x80, "OurClass"), $unserialized => true }

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "TheirClass" } }
  -> TheirClass { $foo => "yes", $__pclass => Binary(0x80, "TheirClass"), $unserialized => true }

/* typemap: [ "root" => "OurClass" ] */
{ foo: "yes", "__pclass" : { "$type": "80", "$binary": "TheirClass" } }
  -> TheirClass { $foo => "yes", $__pclass => Binary(0x80, "TheirClass"), $unserialized => true }

/* typemap: [ 'root' => 'YourClass' ] */
{ foo: "yes", "__pclass" : { "$type": "80", "$binary": "YourClass" } }
  -> YourClass { $foo => 'yes', $__pclass => Binary(0x80, 'YourClass'), $unserialized => true }

/* typemap: [ 'root' => 'array', 'document' => 'array' ] */
{ "foo": "yes", "bar" : false }
  -> [ "foo" => "yes", "bar" => false ]

{ "foo": "no", "array" : [ 5, 6 ] }
  -> [ "foo" => "no", "array" => [ 5, 6 ] ]

{ "foo": "no", "obj" : { "embedded" : 3.14 } }
  -> [ "foo" => "no", "obj" => [ "embedded => 3.14 ] ]

{ "foo": "yes", "__pclass": "MyClass" }
  -> [ "foo" => "yes", "__pclass" => "MyClass" ]

{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MyClass" } }
  -> [ "foo" => "yes", "__pclass" => Binary(0x80, "MyClass") ]

{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "OurClass" } }
  -> [ "foo" => "yes", "__pclass" => Binary(0x80, "OurClass") ]

/* typemap: [ 'root' => 'object', 'document' => 'object' ] */
{ "foo": "yes", "__pclass": { "$type": "80", "$binary": "MyClass" } }
  -> stdClass { $foo => "yes", "__pclass" => Binary(0x80, "MyClass") }

add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top