文档菜单
文档首页
/ / /
PHP 库手册
/

自定义数据类型

注意

本教程解释了使用MongoDB\BSON\Persistable 接口在 MongoDB 扩展中找到。考虑使用编解码器来解耦 MongoDB 持久化逻辑和您的业务逻辑。请参阅编解码器教程 中的示例。

MongoDB PHP 扩展和库支持在序列化和反序列化过程中自定义类。这可能有用的情况之一是如果您想存储包含时区信息的日期/时间信息,而 PHP 的 DateTimeImmutable 类在某个时间点存储。

当扩展与服务器通信时,它会将 PHP 变量(包括对象)序列化为 BSON,并在从服务器接收数据时将 BSON 反序列化为 PHP 变量。

可以通过实现MongoDB\BSON\Persistable接口来影响行为。如果一个类实现了这个接口,那么在序列化时将调用bsonSerialize方法。此方法负责返回一个数组或stdClass对象以转换为BSON并存储在数据库中。这些数据将在从数据库读取时用于重建对象。

以下是一个示例,我们展示了LocalDateTime类。该类包装了MongoDB\BSON\UTCDateTime数据类型和时区。

<?php
/* Custom document class that stores a UTCDateTime and time zone and also
* implements the UTCDateTime interface for portability. */
class LocalDateTime implements \MongoDB\BSON\Persistable, \MongoDB\BSON\UTCDateTimeInterface
{
private $utc;
private $tz;
public function __construct($milliseconds = null, \DateTimeZone $timezone = null)
{
$this->utc = new \MongoDB\BSON\UTCDateTime($milliseconds);
if ($timezone === null) {
$timezone = new \DateTimeZone(date_default_timezone_get());
}
$this->tz = $timezone;
}
?>

As it implements the MongoDB\BSON\Persistable interface, the class is required to implement the bsonSerialize and bsonUnserialize methods. In the bsonSerialize method, we return an array with the two values that we need to persist: the point in time in milliseconds since the Epoch, represented by a MongoDB\BSON\UTCDateTime object, and a string containing the Olson time zone identifier

<?php
public function bsonSerialize()
{
return [
'utc' => $this->utc,
'tz' => $this->tz->getName(),
];
}
?>

此外,扩展还会将__pclass字段添加到文档中,并将其存储在数据库中。此字段包含PHP类名,以便在反序列化时扩展知道使用哪个类来重新创建存储的对象。

当从数据库中读取文档时,扩展会检测是否存在一个 __pclass 字段,然后执行 MongoDB\BSON\Persistable::bsonUnserialize 方法,该方法负责恢复对象的原始状态。

下面的代码确保 utctz 字段中的数据是正确的时间,然后将它们的值分配给两个私有属性。

<?php
public function bsonUnserialize(array $data)
{
if ( ! isset($data['utc']) || ! $data['utc'] instanceof \MongoDB\BSON\UTCDateTime) {
throw new Exception('Expected "utc" field to be a UTCDateTime');
}
if ( ! isset($data['tz']) || ! is_string($data['tz'])) {
throw new Exception('Expected "tz" field to be a string');
}
$this->utc = $data['utc'];
$this->tz = new \DateTimeZone($data['tz']);
}
?>

您可能已经注意到,该类还实现了 MongoDB\BSON\UTCDateTimeInterface 接口。该接口定义了 MongoDB\BSON\UTCDateTime 类的两个非构造方法。

建议现有的 BSON 类的包装器实现各自的接口(例如,MongoDB\BSON\UTCDateTimeInterface),以便包装器对象可以在与原始未包装版本相同的上下文中使用。还建议您始终对接口(例如,MongoDB\BSON\UTCDateTimeInterface)进行类型提示,而不是对具体的类(例如,MongoDB\BSON\UTCDateTime)进行类型提示,因为这将防止包装对象被接受到方法中。

在我们的新toDateTime方法中,我们返回一个设置了本地时区的DateTime对象,而不是MongoDB\BSON\UTCDateTime在返回值中通常使用的UTC时区。

<?php
public function toDateTime()
{
return $this->utc->toDateTime()->setTimezone($this->tz);
}
public function __toString()
{
return (string) $this->utc;
}
}
?>

定义了类之后,我们就可以在我们的文档中使用它。下面的代码片段演示了从LocalDateTime对象到BSON,然后回到LocalDateTime的往返过程。

<?php
$bson = MongoDB\BSON\Document::fromPHP(['date' => new LocalDateTime]);
$document = $bson->toPHP();
var_dump($document);
var_dump($document->date->toDateTime());
?>

输出结果如下

object(stdClass)#1 (1) {
["date"]=>
object(LocalDateTime)#2 (2) {
["utc":"LocalDateTime":private]=>
object(MongoDB\BSON\UTCDateTime)#3 (1) {
["milliseconds"]=>
string(13) "1533042443716"
}
["tz":"LocalDateTime":private]=>
object(DateTimeZone)#4 (2) {
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/London"
}
}
}
object(DateTime)#5 (3) {
["date"]=>
string(26) "2018-07-31 14:07:23.716000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/London"
}

将Olson时区标识符存储在单独的域中,与MongoDB的聚合框架配合良好,它允许根据特定时区进行日期操作、格式化和查询。

返回

专用数据格式