Ce document explique comment les structures composées (c'est-à-dire les documents, les tableaux et les objets) sont converties entre les valeurs BSON et PHP.
Si un tableau est un tableau compact — c'est-à-dire un tableau vide ou les clés commencent à 0 et sont séquentielles sans trous : tableau BSON.
Si le tableau n'est pas compact — c'est-à-dire qu'il a des clés associatives (chaînes), que les clés ne commencent pas à 0, ou qu'il y a des trous : objet BSON.
Un document de niveau supérieur (racine), toujours sérialisé en tant que document BSON.
Ces exemples sérialisent en tant que tableau BSON :
[ 8, 5, 2, 3 ] => [ 8, 5, 2, 3 ] [ 0 => 4, 1 => 9 ] => [ 4, 9 ]
Ces exemples sérialisent en tant qu'objet 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 }
Il est à noter que les cinq exemples sont des extraits d'un document complet, et ne représentent qu'une valeur à l'intérieur d'un document.
Si un objet est de la classe stdClass, sérialiser en tant que document BSON.
Si un objet est une classe supportée qui implémente MongoDB\BSON\Type, alors utiliser la logique de sérialisation BSON pour ce type spécifique. Les instances de MongoDB\BSON\Type (à l'exclusion de MongoDB\BSON\Serializable) ne peuvent être sérialisées que comme valeur de champ de document. Tenter de sérialiser un tel objet en tant que document racine lèvera une MongoDB\Driver\Exception\UnexpectedValueException.
Si un objet est d'une classe inconnue implémentant l'interface MongoDB\BSON\Type, alors une MongoDB\Driver\Exception\UnexpectedValueException est lancée.
Si un objet est d'une classe autre, sans implémenter une interface spéciale, sérialiser en tant que document BSON. Garder seulement les propriétés public, et ignorer les propriétés protected et private.
Si un objet est d'une classe qui implémente MongoDB\BSON\Serializable, appeler MongoDB\BSON\Serializable::bsonSerialize() et utiliser le tableau ou stdClass retourné pour sérialiser en tant que document BSON ou tableau. Le type BSON sera déterminé par les règles suivantes :
Les documents racines doivent être sérialisés en tant que document BSON.
Les objets MongoDB\BSON\Persistable doivent être sérialisés en tant que document BSON.
Si MongoDB\BSON\Serializable::bsonSerialize() retourne un tableau compact, sérialiser en tant que tableau BSON.
Si MongoDB\BSON\Serializable::bsonSerialize() retourne un tableau non-compact ou stdClass, sérialiser en tant qu'objet BSON.
Si MongoDB\BSON\Serializable::bsonSerialize() ne retourne pas un tableau ou stdClass, lance une exception MongoDB\Driver\Exception\UnexpectedValueException.
Si un objet est d'une classe qui implémente l'interface
MongoDB\BSON\Persistable (qui implique
MongoDB\BSON\Serializable), obtenir les
propriétés de manière similaire aux paragraphes précédents, mais
aussi ajouter une propriété
__pclass en tant que valeur binaire, avec un sous-type
0x80
et des données portant le nom de la classe
entièrement qualifié de l'objet qui est sérialisé.
La propriété __pclass est ajoutée au tableau ou à l'objet retourné par MongoDB\BSON\Serializable::bsonSerialize(), ce qui signifie qu'elle écrasera toute clé/propriété __pclass dans la valeur de retour de MongoDB\BSON\Serializable::bsonSerialize(). Si vous voulez éviter ce comportement et définir votre propre valeur __pclass, vous ne devez pas implémenter MongoDB\BSON\Persistable et devriez plutôt implémenter MongoDB\BSON\Serializable directement.
<?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"} 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 = '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=="}}
?>
Les documents BSON peuvent techniquement contenir des clés dupliquées car les documents sont stockés en tant qu'une liste de paire clé-valeur ; cependant, les applications devrait s'abstenir de générer des documents avec des clés dupliquées car le comportement du serveur et du pilote peut être indéfinie. Puisque les objets et tableaux PHP ne peuvent pas avoir de clés dupliquées, les données pourraient aussi être perdu lors du décodage d'un document BSON avec des clés dupliquées.
L'extension mongodb
désérialise les documents BSON
et les tableaux BSON en tant que tableaux PHP. Tant que les tableaux PHP sont
pratiques à utiliser, ce comportement était problématique car différents
types BSON pouvaient être désérialisés en la même valeur PHP (par exemple
{"0": "foo"}
et ["foo"]
) et rendait
impossible d'inférer le type BSON original. Par défaut, l'extension
mongodb
adresse cette préoccupation en s'assurant que les
tableaux BSON et les documents BSON sont convertis en tableaux et objets PHP,
respectivement.
Pour les types composés, il existe trois types de données :
réfère à un document BSON de niveau supérieur seulement
réfère à des documents BSON imbriqués seulement
réfère à un tableau BSON
A part les trois types collectifs, il est aussi possible de configurer des
champs spécifiques dans votre document pour mapper les types de données
mentionnés ci-dessous. Par exemple, le type de carte suivant vous permet de
mapper chaque document intégré dans un tableau "addresses"
à une classe Address et chaque
champ "city"
dans ces documents d'adresse intégrés à une
classe City:
[ 'fieldPaths' => [ 'addresses.$' => 'MyProject\Address', 'addresses.$.city' => 'MyProject\City', ], ]
Chacun de ces trois types de données, ainsi que les mappages spécifiques aux champs, peuvent être mappés contre différents types PHP. Les valeurs de mappage possibles sont:
Un tableau BSON sera désérialisé en un tableau PHP.
Un document BSON (racine ou imbriqué) sans propriété __pclass [1] devient un objet stdClass, avec chaque clé de document BSON définie comme une propriété de stdClass publique.
Un document BSON (racine ou imbriqué) avec une propriété __pclass devient un objet PHP de la classe nommée par la propriété __pclass.
Si la classe nommée implémente l'interface MongoDB\BSON\Persistable, alors les propriétés du document BSON, y compris la propriété __pclass, sont envoyées sous forme de tableau associatif à la fonction MongoDB\BSON\Unserializable::bsonUnserialize() pour initialiser les propriétés de l'objet.
Si la classe nommée n'existe pas ou n'implémente pas l'interface MongoDB\BSON\Persistable, stdClass sera utilisé et chaque clé de document BSON (y compris __pclass) sera définie comme une propriété publique de stdClass.
La fonctionnalité __pclass repose sur le fait que la propriété soit partie d'un document MongoDB récupéré. Si vous utilisez une » projection lors de la recherche de documents, vous devez inclure le champ __pclass dans la projection pour que cette fonctionnalité fonctionne.
"array"
Transforme un tableau BSON en un tableau PHP. Il n'y aura pas de traitement spécial d'une propriété __pclass [1] mais elle peut être définie comme un élément dans le tableau retourné si elle était présente dans le document BSON.
"object"
ou "stdClass"
Transforme un tableau BSON ou un document BSON en un objet stdClass. Il n'y aura pas de traitement spécial d'une propriété __pclass [1] mais elle peut être définie comme une propriété publique dans l'objet retourné si elle était présente dans le document BSON.
"bson"
Transforme un tableau BSON en un MongoDB\BSON\PackedArray et un document BSON en un MongoDB\BSON\Document, indépendamment du fait que le document BSON ait une propriété __pclass [1].
Note: La valeur
bson
n'est disponible que pour les trois types racines, et non dans les mappages spécifiques aux champs.
Définit le nom de la classe à laquelle le document BSON doit être désérialisé. Pour les documents BSON qui incluent des propriétés __pclass, cette classe prendra la priorité.
Si la classe nommée n'existe pas ou n'implémente pas l'interface MongoDB\BSON\Unserializable, une exception MongoDB\Driver\Exception\InvalidArgumentException est lancée.
Si l'objet BSON a une propriété __pclass et que cette classe existe et implémente MongoDB\BSON\Persistable, elle prendra le pas sur la classe fournie dans la carte de type.
Les propriétés du document BSON, y compris la propriété __pclass, seront envoyées sous forme de tableau associatif à la fonction MongoDB\BSON\Unserializable::bsonUnserialize() pour initialiser les propriétés de l'objet.
Les TypeMaps peuvent être définis via la méthode
MongoDB\Driver\Cursor::setTypeMap() sur un objet
MongoDB\Driver\Cursor, ou l'argument
$typeMap
de
MongoDB\BSON\toPHP(),
MongoDB\BSON\Document::toPHP(), et
MongoDB\BSON\PackedArray::toPHP(). Chacune des trois
classes (racine, document, et
array) peut être définie individuellement, en plus des
types spécifiques aux champs.
Si la valeur dans le TypeMap est NULL, cela signifie la même chose que la valeur par défaut pour cet élément.
Ces exemples utilisent les classes suivantes:
qui n'implémente aucune interface
qui implémente MongoDB\BSON\Unserializable
qui implémente MongoDB\BSON\Persistable
qui étends OurClass
La méthode MongoDB\BSON\Unserializable::bsonUnserialize()
de YourClass, OurClass, TheirClass itère sur le tableau et définit les
propriétés sans modifications. Elle ajoute aussi la
propriété $unserialized
à 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") }