Deserialization from BSON
Deserialization from BSON
Deserialization from BSON
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.
For compound types, there are three data types:
- root
-
refers to the top-level BSON document only
- document
-
refers to embedded BSON documents only
- array
-
refers to a BSON array
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', ], ]
Each of those three data types, as well as the
field specific mappings, can be mapped against different PHP types.
The possible mapping values are:
- not set or NULL (default)
-
-
A BSON array will be deserialized as a PHP
array. -
A BSON document (root or embedded) without a
__pclass property [1] becomes a PHP stdClass object, with each BSON document key
set as a public stdClass
property. -
A BSON document (root or embedded) with a
__pclass property [1] becomes a PHP object of
the class name as defined by the __pclass property.If the named class implements the MongoDB\BSON\Persistable
interface, then the properties of the BSON document, including the
__pclass property, are sent as an
associative array to the MongoDB\BSON\Unserializable::bsonUnserialize()
function to initialise the object’s properties.If the named class does not exist or does not
implement the MongoDB\BSON\Persistable interface,
stdClass will be used and each
BSON document key (including __pclass) will be set as a public stdClass property.The __pclass
functionality relies on the property being part of a retrieved
MongoDB document. If you use a projection when querying for documents, you need
to include the __pclass field in the
projection for this functionality to work.
-
- “array”
-
Turns a BSON array or BSON document into a PHP
array. There will be no special treatment of a __pclass property [1], but it may be set as an
element in the returned array if it was present in the BSON
document. - “object” or “stdClass”
-
Turns a BSON array or BSON document into a
stdClass object. There will be
no special treatment of a __pclass
property [1], but it
may be set as a public property in the returned object if it was
present in the BSON document. - any other string
-
Defines the class name that the BSON array or BSON
object should be deserialized as. For BSON objects that include
__pclass properties, that class will
take priority.If the named class does not exist, is not concrete
(i.e. it is abstract or an interface), or does not implement
MongoDB\BSON\Unserializable then an
MongoDB\Driver\Exception\InvalidArgumentException
exception is thrown.If the BSON object has a __pclass property and that class exists and
implements MongoDB\BSON\Persistable it will
supersede the class provided in the type map.The properties of the BSON document, including the __pclass property if it exists, will be sent as
an associative array to the MongoDB\BSON\Unserializable::bsonUnserialize()
function to initialise the object’s properties.
TypeMaps
TypeMaps can be set through the MongoDB\Driver\Cursor::setTypeMap() method
on a MongoDB\Driver\Cursor object, or the
$typeMap argument of MongoDB\BSON\toPHP(). Each of the three
classes (root, document, and array) can
be individually set, in addition to the field specific types.
If the value in the map is NULL, it means the same as the default value for that item.
Examples
These examples use the following classes:
- MyClass
-
which does not implement
any interface - YourClass
-
which implements MongoDB\BSON\Unserializable
- OurClass
-
which implements MongoDB\BSON\Persistable
- TheirClass
-
which extends OurClass
The MongoDB\BSON\Unserializable::bsonUnserialize()
method of YourClass, OurClass, TheirClass iterate over the array
and set the properties without modifications. It also sets the $unserialized property to
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") }