Este documento discute como estruturas compostas (ou seja, documentos, arrays e objetos) são convertidas entre valores BSON e PHP.
Se um array for um array compactado - ou seja, um array vazio ou as chaves começam em 0 e são sequenciais sem lacunas: array BSON.
Se o array não estiver compactado - ou seja, tiver chaves associativas (string), as chaves não começam em 0 ou quando há lacunas:: objeto BSON
Um documento de nível superior (raiz), sempre serializa como um documento BSON.
Estes são serializados como um array BSON:
[ 8, 5, 2, 3 ] => [ 8, 5, 2, 3 ] [ 0 => 4, 1 => 9 ] => [ 4, 9 ]
Estes são serializados como um documento 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 os cinco exemplos são extraídos de um documento completo e representam apenas um valor dentro de um documento.
Se um objeto for da classe stdClass, serialize como um documento BSON.
Se um objeto for de uma classe suportada que implementa MongoDB\BSON\Type, use a lógica de serialização BSON para esse tipo específico. Instâncias MongoDB\BSON\Type, excluindo MongoDB\BSON\Serializable, só podem ser serializadas como um valor de campo de documento. Tentar serializar tal objeto como um documento raiz lançará uma exceção MongoDB\Driver\Exception\UnexpectedValueException
Se um objeto for de uma classe desconhecida que implementa a interface MongoDB\BSON\Type, lance uma exceção MongoDB\Driver\Exception\UnexpectedValueException
Se um objeto for de qualquer outra classe, sem implementar nenhuma interface especial, serialize como um documento BSON. Mantenha apenas propriedades públicas e ignore propriedades protegidas e privadas.
Se um objeto for de uma classe que implementa a interface MongoDB\BSON\Serializable, chame MongoDB\BSON\Serializable::bsonSerialize() e use o array retornado ou stdClass para serializar como um documento ou array BSON. O tipo BSON será determinado pelo seguinte:
Se um objeto for de uma classe que implementa a
interface MongoDB\BSON\Persistable (o que
implica MongoDB\BSON\Serializable), obtenha
as propriedades de maneira semelhante à parágrafos anteriores, mas
também adicione uma propriedade adicional
__pclass como um valor binário, com subtipo
0x80 e dados contendo o nome completo da classe do objeto
que está sendo serializado.
A propriedade __pclass é adicionada ao array ou objeto retornado por MongoDB\BSON\Serializable::bsonSerialize(), o que significa que ela substituirá qualquer chave/propriedade __pclass no valor de retorno MongoDB\BSON\Serializable::bsonSerialize(). Se você quiser evitar esse comportamento e definir seu próprio valor __pclass, você não deve implementar MongoDB\BSON\Persistable e, em vez disso, deve implementar MongoDB\BSON\Serializable diretamente.
<?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"}
/**
* Aninhando Classes Serializáveis
*/
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 uma classe raiz
// ["foo", "bar"] como um valor aninhado
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=="}}
?>Os documentos BSON tecnicamente podem conter chaves duplicadas porque os documentos são armazenados como uma lista de pares chave-valor; no entanto, as aplicações devem evitar a geração de documentos com chaves duplicadas, pois o comportamento do servidor e do driver pode ser indefinido. Como os objetos e arrays do PHP não podem ter chaves duplicadas, os dados também podem ser perdidos ao decodificar um documento BSON com chaves duplicadas.
A extensão mongo herdada desserializou
documentos BSON e arrays como arrays PHP. Embora arrays PHP sejam c
onvenientes para trabalhar, esse comportamento era problemático porque diferentes
tipos de BSON poderiam desserializar para o mesmo valor PHP (por exemplo,
{"0": "foo"} e ["foo"]) e torna
impossível inferir o tipo BSON original. Por padrão, a
extensão mongodb aborda essa preocupação garantindo que arrays e
documentos BSON sejam convertidos em arrays e objetos PHP, respectivamente.
Para tipos compostos, existem três tipos de dados:
Além dos três tipos de coletivos, também é possível configurar
campos específicos em seu documento para mapear os tipos de dados mencionados abaixo.
Como exemplo, o seguinte mapa de tipos permite a você
mapear cada documento incorporado dentro de um array "addresses" para
uma classe Address e cada
"city" dentro desses documentos de endereço incorporados para
uma classe City:
[
'fieldPaths' => [
'addresses.$' => 'MyProject\Address',
'addresses.$.city' => 'MyProject\City',
],
]
Cada um desses três tipos de dados, bem como os mapeamentos específicos de campo, podem ser mapeados em diferentes tipos de PHP. Os possíveis valores de mapeamento são:
Uma propriedade __pclass só é considerada existente se existir uma propriedade com esse nome, e for um valor Binário, e o subtipo do valor Binário for 0x80. Se alguma dessas três condições não for atendida, a propriedade __pclass não existe e deverá ser tratada como qualquer outra propriedade normal.
torna-se um objeto PHP stdClass, com cada chave de documento BSON definida como uma propriedade pública stdClass."array""object" ou "stdClass""bson"Nota: O valor
bsonestá disponível apenas para os três tipos de raiz, não nos mapeamentos específicos do campo.
TypeMaps podem ser definidos através do
método MongoDB\Driver\Cursor::setTypeMap() em um
objeto MongoDB\Driver\Cursor ou do
argumento $typeMap de
MongoDB\BSON\toPHP(),
MongoDB\BSON\Document::toPHP() e
MongoDB\BSON\PackedArray::toPHP(). Cada uma das três
classes (root, document e
array) pode ser definida individualmente, além dos tipos
específicos de campo.
Se o valor no mapa for NULL, significa o mesmo que o valor padrão para esse item.
Esses exemplos usam as seguintes classes:
O método MongoDB\BSON\Unserializable::bsonUnserialize()
de YourClass, OurClass, TheirClass itera sobre o array e define
as propriedades sem modificações. Ele também define
a propriedade $unserialized como 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") }