PHP 8.4.0 RC4 available for testing

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

Este documento trata sobre los métodos de cómo las estructuras compuestas (documentos, arrays, objetos) se hacen persistentes a través de los controladores y de cómo son llevadas de vuelta a PHP.

Serialización a BSON

Arrays

Si un array es un array compacto, esto es, las claves empiezan en 0 y están en secuencia sin huecos: array BSON.

Si el array no es compacto, esto es, tiene claves asociativas (string), las claves no comienzan en 0, o cuando hay huecos: objeto BSON

Un documento del más alto nivel (raíz), siempre se serializa como un documento BSON.

Ejemplos

Los siguientes arrays se serializan como arrays BSON:

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

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

Observe que los cinco ejemplos son fragmentos de un documento completo que representan solamente un valor dentro de un documento.

Objetos

Si un objeto es de la clase stdClass se serializa como un documento BSON.

Si un objeto es de una clase admitida que implementa MongoDB\BSON\Tipo, se utiliza la lógica de serialización BSON para un tipo específico. Las instancias de MongoDB\BSON\Tipo (excluyendo MongoDB\BSON\Serializable solo podrían ser serializadas como un valor de campo de documento. Intentar serializar tales objetos como un documento raíz lanzará una MongoDB\Driver\Exception\UnexpectedValueException

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

Si un objeto es de cualquier otra clase que no implemente ninguna interfaz especial, se serializa como un documento BSON. Se mantienen solo las propiedades public y se ignoran las propiedades protected y private.

Si un objeto es de una clase que implementa la interfaz MongoDB\BSON\Serializable, se llama a MongoDB\BSON\Serializable::bsonSerialize() y se utiliza el array u objeto stdClass devuelto para serilizarlo como un documento BSON o array. El tipo BSON será determinado como sigue:

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

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

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

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

  5. Si MongoDB\BSON\Serializable::bsonSerialize() no devuelve un array u objeto stdClass, se lanza una excepción de tipo MongoDB\Driver\Exception\UnexpectedValueException.

Si un objeto es de una clase que implementa la interfaz MongoDB\BSON\Persistable (lo que implica que MongoDB\BSON\Serializable obtiene las propiedades de una forma similar a los párrafos anteriores, aunque también añade una propiedad adicional __pclass como un valor Binary, con subtipo 0x80 y datos soportando el nombre de la clase completamente cualificado del objeto que se está serializando.

La propiedad __pclass se añade al array u objeto devuelto por MongoDB\BSON\Serializable::bsonSerialize(), lo que significa que se sobrescribirá cualquier clave/propiedad __pclass en el valor devuelto de MongoDB\BSON\Serializable::bsonSerialize(). Para evitar este funcionamiento y establecer un valor de __pclass propio, no se debe implementar MongoDB\BSON\Persistable y, en su lugar, se deerí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";
function
bsonSerialize() {
return [
'foo' => $this->foo, 'prot' => $this->prot ];
}
}
// => { "foo" : 42, "prot" : "wine" }

class AnotherClass2 implements MongoDB\BSON\Serializable {
public
$foo = 42;
function
bsonSerialize() {
return
$this;
}
}
// => MongoDB\Driver\Exception\UnexpectedValueException("bsonSerialize() did not return an array or stdClass")

class AnotherClass3 implements MongoDB\BSON\Serializable {
private
$elements = [ 'foo', 'bar' ];
function
bsonSerialize() {
return
$this->elements;
}
}
// => { "0" : "foo", "1" : "bar" }

class ContainerClass implements MongoDB\BSON\Serializable {
public
$things = AnotherClass4 implements MongoDB\BSON\Serializable {
private
$elements = [ 0 => 'foo', 2 => 'bar' ];
function
bsonSerialize() {
return
$this->elements;
}
}
function
bsonSerialize() {
return [
'things' => $this->things ];
}
}
// => { "things" : { "0" : "foo", "2" : "bar" } }

class ContainerClass implements MongoDB\BSON\Serializable {
public
$things = AnotherClass5 implements MongoDB\BSON\Serializable {
private
$elements = [ 0 => 'foo', 2 => 'bar' ];
function
bsonSerialize() {
return
array_values($this->elements);
}
}
function
bsonSerialize() {
return [
'things' => $this->things ];
}
}
// => { "things" : [ "foo", "bar" ] }

class ContainerClass implements MongoDB\BSON\Serializable {
public
$things = AnotherClass6 implements MongoDB\BSON\Serializable {
private
$elements = [ 'foo', 'bar' ];
function
bsonSerialize() {
return (object)
$this->elements;
}
}
function
bsonSerialize() {
return [
'things' => $this->things ];
}
}
// => { "things" : { "0" : "foo", "1" : "bar" } }

class UpperClass implements MongoDB\BSON\Persistable {
public
$foo = 42;
protected
$prot = "wine";
private
$fpr = "cheese";
function
bsonSerialize() {
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.

The legacy mongo extension deserialized both BSON documents and arrays as PHP arrays. While PHP arrays are convenient to work with, this behavior was problematic because different BSON types could deserialize to the same PHP value (e.g. {"0": "foo"} and ["foo"]) and make it impossible to infer the original BSON type. By default, the current driver addresses this concern by ensuring that BSON arrays and documents are converted to PHP arrays and objects, respectively.

Para tipos compuestos, existen tres tipos de datos:

root

se refiere al documento BSON de más alto nivel solamente

document

se refiere a docuemtnos BSON embebidos solamente

array

se refiere a un array BSON

Besides the three collective types, it is also possible to configure specific fields in your document to map to the data types mentioned below. As an example, the following type map allows you to map each embedded document within an "addresses" array to an Address class and each "city" field within those embedded address documents to a City class:

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

Cada uno de estos tres tipos de datos se pueden hacer corresponder con diferentes tipos de PHP. Los posibles valores de correspondencia son:

no establecido o NULL (es el predeterminado)

  • Un array BSON será deserializado como un array de PHP.

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

  • Un documento BSON (raíz o embebido) con una propiedad __pclass [1] se convierte en un objeto de PHP del nombre de la clase definida por la propiedad __pclass.

    Si la clase con nombre implementa la intefaz MongoDB\BSON\Persistable, las propiedades del documento BSON, incluyendo la propiedad __pclass, son enviadas como un array asociativo a la función bsonUnserialize() para inicializar la propiedades del objeto.

    Si la clase con nombre no existe o no implementa la interfaz MongoDB\BSON\Persistable, se empleará stdClass y cada clave del documento BSON (incluyendo __pclass) será establecida a una propiedad stdClass pública.

"array"

Convierte un array BSON o documento BSON en un array de PHP. No habrá ningún tratamiento especial de una propiedad __pclass [1], aunque se podría establecer como un elemento del array devuelto si estaba presente el el documento BSON.

"object" o "stdClass"

Convierte un array BSON o documento BSON a un objeto stdClass. No habrá ningún tratamiento especial de una propiedad __pclass [1], aunque se podría establecer como propiedad pública del objeto devuelto si estaba presente en el documento BSON.

cualquier otro string

Define el nombre de la clase a la que debe ser deserializado el array BSON u objeto BSON. Para objetos BSON que incluyan propiedades __pclass, esta clase tomará prioridad.

Si la clase citada no existe, no es concreta (esto es, es abstracta o es una interfaz), o no implementa MongoDB\BSON\Unserializable, se lanzará una excepción MongoDB\Driver\Exception\InvalidArgumentException.

Si el objeto BSON posee una propiedad __pclass y esa clase existe e implementa MongoDB\BSON\Persistable, sustituirá a la clase proporcionada en el mapa de tipo.

Las propiedades del documento BSON, incluyendo la propiedad __pclass si existiera, será enviada como un array asociativo a la función bsonUnserialize() para inicializar las propiedades del objeto.

TypeMaps

TypeMaps se puede establecer a través del método MongoDB\Driver\Cursor::setTypeMap() en un objeto MongoDB\Driver\Cursor o del argumento $typeMap de MongoDB\BSON\toPHP(). Cada una de las tres clases (root, document and array) se pueden establecer individualmente.

Si el valor del mapa es NULL, significa lo mismo que el valor predeterminado para ese elemento.

Ejemplos

Estos ejemplos utilizan las siguientes clases:

MiClase

la cual no implementa ninguna interfaz

TuClase

que implementa MongoDB\BSON\Unserializable

NuestraClase

que implementa MongoDB\BSON\Persistable

SuClase

que extiende NuestraClase

El método MongoDB\BSON\Unserializable::bsonUnserialize() de TuClase, NuestraClase, SuClase recorre el array y establece las propiedades sin modificaciones. También establece la propiedad $unserialized a true:

<?php

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

/* typemap: [] (all defaults) */
{ "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