Files
php-doc-ru/reference/mongodb/architecture.xml

985 lines
42 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: e8ac70bf549a723cb36465667a6109d9933b8619 Maintainer: sergey Status: ready -->
<!-- Reviewed: no -->
<chapter xml:id="mongodb.architecture" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<titleabbrev>Архитектура и внутреннее устройство драйвера</titleabbrev>
<title>Обзор архитектуры драйвера и её особенностей</title>
<section xml:id="mongodb.overview">
<titleabbrev>Архитектура</titleabbrev>
<title>Обзор архитектуры</title>
<para>
Раздел объясняет, как разные части PHP-драйвера сочетаются
друг с другом, от базовых системных библиотек, через PHP-модули и до
PHP-библиотек на самом верху.
</para>
<para>
<mediaobject>
<alt>
Схема архитектуры PHP-драйвера MongoDB.
Самый низкий уровень драйвера — системные модули: libmongoc, libbson и libmongocrypt.
Средний уровень — PHP-модуль MongoDB.
Верхний уровень — пользовательское PHP-окружение,
которое включает PHP-модуль MongoDB и пакеты более высокого уровня наподобие фреймворков и приложений.
</alt>
<imageobject>
<imagedata fileref="en/reference/mongodb/images/driver_arch.svg" width="625" depth="450" format="SVG" />
</imageobject>
</mediaobject>
</para>
<para>
Наверху стека расположена
<link xlink:href="&url.mongodb.library;">библиотека PHP</link>, которая распространяется
в виде <link xlink:href="&url.packagist.package;/mongodb/mongodb">пакета Composer</link>.
Эта библиотека предоставит API, согласованный с другими
<link xlink:href="&url.mongodb.drivers;">драйверами</link> MongoDB,
и реализует междрайверные
<link xlink:href="&url.mongodb.specs;">спецификации</link>.
Хотя модуль можно использовать напрямую, библиотека даёт минимальные накладные расходы
и должна быть общей зависимостью для большей части приложений, построенных с MongoDB.
</para>
<para>
На уровень ниже библиотеки располагается PHP-модуль, который распространяется
через репозиторий <link xlink:href="&url.pecl.package;mongodb">PECL</link>.
Модуль образует связующую прослойку между PHP и системными библиотеками
(<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>,
<link xlink:href="&url.mongodb.libbson;">libbson</link>
и <link xlink:href="&url.mongodb.libmongocrypt;">libmongocrypt</link>).
Этот публичный API предлагает только самую базовую функциональность:
<simplelist>
<member>Управление соединением</member>
<member>BSON кодирование и декодирование</member>
<member>Сериализация документа объекта (для поддержки библиотек ODM)</member>
<member>Выполнение команд, запросы и запись операций</member>
<member>Обработка курсоров для команд и результатов запроса</member>
</simplelist>
</para>
<para>
<table>
<title>Исходный код драйвера и проекты JIRA</title>
<tgroup cols="3">
<thead>
<row>
<entry>Проект</entry>
<entry>GitHub</entry>
<entry>JIRA</entry>
</row>
</thead>
<tbody>
<row>
<entry>PHP библиотека</entry>
<entry><link xlink:href="&url.mongodb.github.phplib;">mongodb/mongo-php-library</link></entry>
<entry><link xlink:href="&url.mongodb.jira.phplib;">PHPLIB</link></entry>
</row>
<row>
<entry>PHP-модуль</entry>
<entry><link xlink:href="&url.mongodb.github.phpc;">mongodb/mongo-php-driver</link></entry>
<entry><link xlink:href="&url.mongodb.jira.phpc;">PHPC</link></entry>
</row>
</tbody>
</tgroup>
</table>
</para>
</section>
<section xml:id="mongodb.connection-handling">
<titleabbrev>Соединения</titleabbrev>
<title>Обработка и сохранение соединения</title>
&mongodb.note.forking;
<section>
<title>Сохранение соединения и топологии (версия PHP начиная с 1.2.0)</title>
<para>
Каждая версия модуля начиная с 1.2.0 сохраняет клиентский объект
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>
в рабочем процессе PHP, что позволяет ему повторно использовать соединения с базой данных,
состояния аутентификации <emphasis>и</emphasis> информацию о топологии в
нескольких запросах.
</para>
<para>
Когда вызывается метод <methodname>MongoDB\Driver\Manager::__construct</methodname>,
из его аргументов создаётся хеш (т. е. строка URI и параметры
массива). Модуль попытается найти ранее сохранённый клиентский объект
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link> для
этого хеша. Если существующий клиент не может быть найден для хеша, будет создан
новый клиент и сохранён для будущего использования. Это поведение можно выключить
через параметр драйвера <literal>"disableClientPersistence"</literal>.
</para>
<para>
Каждый клиент содержит свои собственные подключения к базе данных и представление
топологии сервера (например, автономный, набор реплик, кластер сегментов). Сохраняя
клиент между PHP-запросами, модуль может переиспользовать установленные
подключения к базе данных и устранять необходимость
<link xlink:href="&url.mongodb.sdam;">обнаружения топологии сервера</link>
при каждом запросе.
</para>
<para>
Рассмотрим следующий пример:
</para>
<programlisting role="php">
<![CDATA[
<?php
$managers = [
new MongoDB\Driver\Manager('mongodb://127.0.0.1'),
new MongoDB\Driver\Manager('mongodb://127.0.0.1'),
new MongoDB\Driver\Manager('mongodb://127.0.0.1:27017'),
new MongoDB\Driver\Manager('mongodb://rs1.example.com,rs2.example.com/', ['replicaSet' => 'myReplicaSet']),
];
foreach ($managers as $manager) {
$manager->executeCommand('test', new MongoDB\Driver\Command(['ping' => 1]));
}
?>
]]>
</programlisting>
<para>
Первые два объекта Manager будут использовать один и тот же
клиент <link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>, поскольку
их аргументы конструктора идентичны. Третий и четвёртый объекты будут
использовать каждый свой клиент. Всего будет создано три клиента, и
процесс PHP, выполняющий этот скрипт, откроет два соединения с
адресом <literal>127.0.0.1</literal> и одно соединение с каждым из
адресов: <literal>rs1.example.com</literal> и <literal>rs2.example.com</literal>.
Если драйвер обнаруживает дополнительных членов набора реплик после выполнения команд
<literal>hello</literal>, он также открывает дополнительные подключения
к этим серверам.
</para>
<para>
Если этот же процесс снова выполнит сценарий во втором запросе, эти три
клиента будут использованы повторно, а новых подключений установлено не будет. В зависимости
от того, как давно был обработан предыдущий запрос, модулю может потребоваться выполнить
дополнительные команды <literal>hello</literal> для обновления своего представления
топологий.
</para>
</section>
<section>
<title>Сохранение сокетов (версии PHP до 1.2.0)</title>
<para>
Версии модуля до 1.2.0 используют API-интерфейс PHP-потоков
для подключений к базам данных через внутренний API-интерфейс библиотеки
<link xlink:href="&url.mongodb.libmongoc;">libmongoc</link>, чтобы назначить пользовательские
обработчики для связи с сокетами; однако новый клиент libmongoc
создаётся для каждого менеджера <classname>MongoDB\Driver\Manager</classname>. В результате
модуль сохраняет отдельные соединения с базой данных, но не информацию о состоянии аутентификации
или топологии. Поэтому модулю приходится выдавать
команды в начале каждого запроса, чтобы проверить подлинность
и <link xlink:href="&url.mongodb.sdam;">обнаружить топологию сервера</link>.
</para>
<para>
Соединения с базой данных сохраняются как хеш хоста,
порта и строки URI-идентификатора сервера, которую передавали в конструктор
менеджера <classname>MongoDB\Driver\Manager</classname>. Параметры массива конструктора
не включаются в этот хеш.
</para>
<note>
<simpara>
Версии модуля &gt;= 1.1.8 and &lt; 1.2.0 не сохраняют сокеты
для SSL-соединений. Смотрите
<link xlink:href="&url.mongodb.jira.phpc;-720">PHPC-720</link> для получения
дополнительной информации.
</simpara>
</note>
<para>
Несмотря на недостатки, которые связаны с сохранением SSL-соединений и информацией о топологии,
эта версия модуля поддерживает все
<link linkend="context.ssl">параметры SSL-контекста</link>, поскольку использует
API-интерфейс потоков PHP.
</para>
</section>
</section>
<section xml:id="mongodb.persistence">
<titleabbrev>Сохранение данных</titleabbrev>
<title>Сериализация и десериализация PHP-переменных в модуле MongoDB</title>
<para>
В документе обсуждается, как составные структуры наподобие документов, массивов
и объектов преобразовываются между значениями формата BSON и PHP-значениями.
</para>
<section xml:id="mongodb.persistence.serialization">
<title>Сериализация в BSON</title>
<section>
<title>Массивы</title>
<para>
Если массив представляет собой <emphasis>упакованный массив</emphasis>
то есть пустой массив или ключи начинаются
с 0 и идут последовательно без пробелов: <emphasis>BSON-массив</emphasis>.
</para>
<para>
Если массив не упакован — то есть содержит ассоциативные (строковые) ключи,
ключи не начинаются с 0 или содержат пробелы: <emphasis>BSON-объект</emphasis>
</para>
<para>
Документ верхнего уровня (корневой) <emphasis>всегда</emphasis> сериализуется
как BSON-документ.
</para>
<section>
<title>Примеры</title>
<para>
Эти PHP-массивы сериализуются как BSON-массив:
</para>
<programlisting role="text">
<![CDATA[
[8, 5, 2, 3] => [8, 5, 2, 3]
[0 => 4, 1 => 9] => [4, 9]
]]>
</programlisting>
<para>
Эти PHP-массивы сериализуются как BSON-документ:
</para>
<programlisting role="text">
<![CDATA[
[0 => 1, 2 => 8, 3 => 12] => {"0": 1, "2": 8, "3": 12}
["foo" => 42] => {"foo": 42}
[1 => 9, 0 => 10] => {"1": 9, "0": 10}
]]>
</programlisting>
<para>
Обратите внимание, что пять приведённых примеров — <emphasis>выдержки</emphasis> из полного
документа и представляют только <emphasis>одно</emphasis> значение внутри
документа.
</para>
</section>
</section>
<section>
<title>Объекты</title>
<para>
Если объект принадлежит типу <classname>stdClass</classname>, он сериализуется
как <emphasis>BSON-документ</emphasis>.
</para>
<para>
Если объект — поддерживаемый класс, который реализует
интерфейс <interfacename>MongoDB\BSON\Type</interfacename>, используется
логика сериализации BSON для этого конкретного типа.
Экземпляры с типом <interfacename>MongoDB\BSON\Type</interfacename> (исключая
тип <interfacename>MongoDB\BSON\Serializable</interfacename>) можно
сериализовать только как значение поля документа. Попытка сериализовать такой объект
как корневой документ выбросит исключение
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>.
</para>
<para>
Если объект принадлежит неизвестному классу, который реализует интерфейс
<interfacename>MongoDB\BSON\Type</interfacename>, выбрасывается исключение
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>.
</para>
<para>
Если объект принадлежит какому-либо другому классу без реализации какого-либо специального
интерфейса, он сериализуется как <emphasis>BSON-документ</emphasis>. Остаются только
открытые (<emphasis>public</emphasis>) свойства, а защищённые (<emphasis>protected</emphasis>)
и закрытые (<emphasis>private</emphasis>) свойства игнорируются.
</para>
<para>
Если объект принадлежит к классу, который реализует интерфейс
<interfacename>MongoDB\BSON\Serializable</interfacename>, вызывают
метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
и сериализуют массив или <classname>stdClass</classname>, которые возвращает метод,
как BSON-документ или как BSON-массив. Тип BSON определят следующие условия:
</para>
<para>
<orderedlist>
<listitem>
<para>Корневые документы требуется сериализовать
как BSON-документ.
</para>
</listitem>
<listitem>
<para>
Объекты с типом <interfacename>MongoDB\BSON\Persistable</interfacename> требуется
сериализовать как BSON-документы.
</para>
</listitem>
<listitem>
<para>
Если метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
возвращает упакованный массив, его сериализуют как BSON-массив.
</para>
</listitem>
<listitem>
<para>
Если метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
возвращает неупакованный массив или объект <classname>stdClass</classname>,
его сериализуют как BSON-документ.
</para>
</listitem>
<listitem>
<para>
Если метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>
не вернул массив или объект <classname>stdClass</classname>, выбрасывается исключение
<classname>MongoDB\Driver\Exception\UnexpectedValueException</classname>.
</para>
</listitem>
</orderedlist>
</para>
<para>
Если объект принадлежит классу, который реализует интерфейс
<interfacename>MongoDB\BSON\Persistable</interfacename> (что
подразумевает реализацию метода <interfacename>MongoDB\BSON\Serializable</interfacename>),
свойства остаются по аналогии с предыдущими абзацами,
но <emphasis>также</emphasis> добавляется дополнительное свойство
<property>__pclass</property> в виде Binary-значения с подтипом
<literal>0x80</literal> и данными, которые содержат полное имя класса объекта,
который сериализуется.
</para>
<para>
Свойство <property>__pclass</property> добавляется в массив или
объект, который возвращает метод
<methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>,
что означает, что оно перезапишет любой ключ или свойство <property>__pclass</property>
в значении, которое возвращает метод <methodname>MongoDB\BSON\Serializable::bsonSerialize</methodname>.
Если требуется избежать такого поведения и установить собственное значение
<property>__pclass</property>, <emphasis>вместо</emphasis>
реализации интерфейса <interfacename>MongoDB\BSON\Persistable</interfacename>
следует напрямую реализовать интерфейс
<interfacename>MongoDB\BSON\Serializable</interfacename>.
</para>
<section>
<title>Примеры</title>
<programlisting role="php">
<![CDATA[
<?php
class stdClass
{
public $foo = 42;
} // => {"foo": 42}
class MyClass
{
public $foo = 42;
protected $prot = 'вино';
private $fpr = 'сыр';
} // => {"foo": 42}
class AnotherClass1 implements MongoDB\BSON\Serializable
{
public $foo = 42;
protected $prot = 'вино';
private $fpr = 'сыр';
public function bsonSerialize(): array
{
return ['foo' => $this->foo, 'prot' => $this->prot];
}
} // => {"foo": 42, "prot": "вино"}
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"}
/**
* Вложенные сериализуемые классы
*/
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 = 'вино';
private $fpr = 'сыр';
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": "вино", "__pclass": {"$type": "80", "$binary": "VXBwZXJDbGFzcw=="}}
?>
]]>
</programlisting>
</section>
</section>
</section>
<section xml:id="mongodb.persistence.deserialization">
<title>Десериализация из BSON</title>
&mongodb.warning.duplicate-keys;
<para>
Устаревший модуль <code>mongo</code> десериализовывал
BSON-документы и BSON-массивы в PHP-массивы. Хотя с PHP-массивами
удобно работать, такое поведение было проблематичным, поскольку разные
BSON-типы могли десериализоваться до одного и того же PHP-значения (например,
<literal>{"0": "foo"}</literal> и <literal>["foo"]</literal>), что делало
невозможным определение оригинального BSON-типа. По умолчанию модуль <code>mongodb</code>
решает эту проблему и гарантирует, что BSON-массивы преобразуются в PHP-массивы, а BSON-документы
в PHP-объекты.
</para>
<para>
Для составных типов существует три типа данных:
</para>
<para>
<variablelist>
<varlistentry>
<term>root</term>
<listitem>
<para>
относится <emphasis>только</emphasis> к BSON-документу верхнего уровня
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>document</term>
<listitem>
<para>
относится <emphasis>только</emphasis> к встроенным BSON-документам
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>array</term>
<listitem>
<para>
относится к BSON-массивам
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Помимо трёх групповых типов, также можно настроить
определённые поля в документе для сопоставления с типами данных, как указывает следующий фрагмент кода.
В качестве примера, следующая карта типов позволяет
сопоставить каждый встроенный документ в массиве <literal>«addresses»</literal>
с классом <classname>Address</classname>, <emphasis>а</emphasis> каждое
поле <literal>«city»</literal> в этих документах с встроенным адресом
с классом <classname>City</classname>:
<programlisting role="text">
<![CDATA[
[
'fieldPaths' => [
'addresses.$' => 'MyProject\Address',
'addresses.$.city' => 'MyProject\City',
],
]
]]>
</programlisting>
</para>
<para>
Каждый из этих трёх типов данных, а также сопоставления конкретных полей
можно сопоставить с различными типами PHP. Возможные значения сопоставления:
</para>
<para>
<variablelist>
<varlistentry>
<term><emphasis>не указано</emphasis> или <type>NULL</type> (по умолчанию)</term>
<listitem>
<para>
<itemizedlist>
<listitem>
<para>
BSON-массив будет десериализован как PHP-массив (<type>array</type>).
</para>
</listitem>
<listitem>
<para>
BSON-документ (корневой или встроенный) без свойства
<property>__pclass</property>
<footnote xml:id="mongodb.pclass">
<para>
Свойство __pclass считается существующим, только
если существует свойство с таким именем, и оно представляет собой Binary-значение,
а подтип Binary значения равен 0x80. Если какое-либо из этих трёх
условий не выполняется, свойство __pclass не существует
и должно рассматриваться как любое другое обычное свойство.
</para>
</footnote>
становится PHP-объектом <classname>stdClass</classname>, причём каждый
ключ BSON-документа устанавливается как открытое
свойство объекта <classname>stdClass</classname>.
</para>
</listitem>
<listitem>
<para>
BSON-документ (корневой или встроенный) со свойством
<property>__pclass</property> <footnoteref linkend="mongodb.pclass"/> становится PHP-объектом
имени класса, как это определяет свойство <property>__pclass</property>.
</para>
<para>
Если именованный класс реализует интерфейс
M<interfacename>MongoDB\BSON\Persistable</interfacename>,
то свойства BSON-документа, включая свойство
<property>__pclass</property>, отправляются как ассоциативный
массив в метод
<methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>,
чтобы инициализировать свойства объекта.
</para>
<para>
Если именованный класс не существует или не реализует интерфейс
<interfacename>MongoDB\BSON\Persistable</interfacename>,
будет использоваться объект <classname>stdClass</classname>, и каждый ключ BSON-документа
(включая свойство <property>__pclass</property>) будет установлен
как открытое свойство объекта <classname>stdClass</classname>.
</para>
<para>
Функциональность свойства <property>__pclass</property> зависит от того, представляет ли
собой свойство часть извлечённого документа БД MongoDB. Если при запросе документов
используется <link linkend="mongodb-driver-query.construct-queryOptions">проекция</link>,
необходимо включить в проекцию поле <property>__pclass</property>,
чтобы эта функциональность работала.
</para>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>«array»</literal></term>
<listitem>
<para>
Превращает BSON-массив или BSON-документ в PHP-массив. Специальной обработки
свойства <property>__pclass</property> <footnoteref linkend="mongodb.pclass"/> не будет,
но его можно установить как элемент в возвращаемом массиве, если он
содержался в BSON-документе.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>«object»</literal> или <literal>«stdClass»</literal></term>
<listitem>
<para>
Превращает BSON-массив или BSON-документ в объект
<classname>stdClass</classname>. Специальной
обработки свойства <property>__pclass</property> <footnoteref linkend="mongodb.pclass"/> не будет,
но его можно установить как открытое свойство в возвращаемом объекте, если оно присутствовало
в BSON-документе.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>«bson»</literal></term>
<listitem>
<para>
Превращает BSON-массив в объект <classname>MongoDB\BSON\PackedArray</classname>,
а BSON-документ в объект <classname>MongoDB\BSON\Document</classname>,
независимо от того, есть ли у BSON-документа свойство <property>__pclass</property>
<footnoteref linkend="mongodb.pclass"/>.
</para>
<note>
<simpara>
Значение <literal>bson</literal> доступно только для трёх корневых типов,
но не в отображениях для конкретных полей.
</simpara>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term>любая другая строка</term>
<listitem>
<para>
Определяет имя класса, который должен десериализовать BSON-массив
или BSON-объект. Для BSON-объектов, которые содержат свойства
<property>__pclass</property>, этот класс будет приоритетным.
</para>
<para>
Если именованный класс не существует, не представляет собой конкретный класс (то есть это
абстрактный класс или интерфейс) или не реализует
интерфейс <interfacename>MongoDB\BSON\Unserializable</interfacename>, выбрасывается исключение
<classname>MongoDB\Driver\Exception\InvalidArgumentException</classname>.
</para>
<para>
Если BSON-объект содержит свойство <property>__pclass</property> и
этот класс существует и реализует
интерфейс <interfacename>MongoDB\BSON\Persistable</interfacename>,
он заменит класс, представленный в карте типов.
</para>
<para>
Свойства BSON-документа, <emphasis>включая</emphasis>
свойство <property>__pclass</property>, если оно существует, отправляются
как ассоциативный массив в метод
<methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>,
чтобы инициализировать свойства объекта.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<section xml:id="mongodb.persistence.typemaps">
<title>TypeMaps</title>
<para>
Функции настройки TypeMaps можно установить методом
<methodname>MongoDB\Driver\Cursor::setTypeMap</methodname> для объекта
<classname>MongoDB\Driver\Cursor</classname> или аргумента
<literal>$typeMap</literal>
в методах <function>MongoDB\BSON\toPHP</function>,
<methodname>MongoDB\BSON\Document::toPHP</methodname>
и <methodname>MongoDB\BSON\PackedArray::toPHP</methodname>. Каждый из трёх
классов (<emphasis>root</emphasis>, <emphasis>document</emphasis>, и
<emphasis>array</emphasis>) можно задать индивидуально, в дополнение
к типам полей.
</para>
<para>
Если значение на карте равно <type>NULL</type>, это означает то же,
что и значение <emphasis>по умолчанию</emphasis> для этого элемента.
</para>
</section>
<section>
<title>Примеры</title>
<para>
В этих примерах используются следующие классы:
</para>
<para>
<variablelist>
<varlistentry>
<term>MyClass</term>
<listitem>
<para>
<emphasis>не</emphasis> реализует интерфейсы
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>YourClass</term>
<listitem>
<para>
реализует интерфейс
<interfacename>MongoDB\BSON\Unserializable</interfacename>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>OurClass</term>
<listitem>
<para>
реализует интерфейс
<interfacename>MongoDB\BSON\Persistable</interfacename>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>TheirClass</term>
<listitem>
<para>
расширяет класс OurClass
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Метод <methodname>MongoDB\BSON\Unserializable::bsonUnserialize</methodname>
классов YourClass, OurClass, OurClass выполняет итерацию по массиву и устанавливает
свойства без изменений. Метод <emphasis>также</emphasis> устанавливает для свойства
<literal>$unserialized</literal> значение &true;:
<programlisting role="php">
<![CDATA[
<?php
function bsonUnserialize(array $map)
{
foreach ($map as $k => $value) {
$this->$k = $value;
}
$this->unserialized = true;
}
?>
]]>
</programlisting>
</para>
<para>
<programlisting role="text">
<![CDATA[
/* typemap: [] (все значения по умолчанию) */
{"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')}
]]>
</programlisting>
</para>
<para>
<programlisting role="text">
<![CDATA[
/* 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}
]]>
</programlisting>
</para>
<para>
<programlisting role="text">
<![CDATA[
/* typemap: ['root' => 'YourClass'] */
{foo: "yes", "__pclass": {"$type": "80", "$binary": "YourClass"}}
-> YourClass {$foo => 'yes', $__pclass => Binary(0x80, 'YourClass'), $unserialized => true}
]]>
</programlisting>
</para>
<para>
<programlisting role="text">
<![CDATA[
/* 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")]
]]>
</programlisting>
</para>
<para>
<programlisting role="text">
<![CDATA[
/* typemap: ['root' => 'object', 'document' => 'object'] */
{"foo": "yes", "__pclass": {"$type": "80", "$binary": "MyClass"}}
-> stdClass {$foo => "yes", "__pclass" => Binary(0x80, "MyClass")}
]]>
</programlisting>
</para>
</section>
</section>
</section>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->