Docs 菜单
Docs 主页
/ / /
PHP 库手册
/

自定义数据类型

注意

本教程介绍如何使用 MongoDB\ BSON\Persistable 实施自定义数据类型 MongoDB扩展中的接口。请考虑改用编解码器,将MongoDB持久性逻辑与业务逻辑分离开来。 有关示例,请参阅编解码器教程

MongoDB PHP 扩展和库在序列化和反序列化时支持自定义类。 这可能有用的一个示例是,如果您想要存储日期/时间信息,并保留 PHP 的 DateTimeImmutable class 存储有一个时间点。

该扩展在与服务器通信时将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;
}
?>

由于它实现了 MongoDB\BSON\Persistable 接口,该类需要实现 bsonSerialize bsonUnserialize 方法。在 bsonSerialize 方法,我们返回一个数组,其中包含需要保留的两个值: 自纪元以来的时间点(以毫秒为单位),用MongoDB \BSON \UTCDateTime string表示 对象,以及一个包含 Olson 时区标识符的 :

<?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 通常在其返回值中使用。

<?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 的聚合框架配合使用,该框架允许根据特定时区进行日期操作、格式化和查询。

后退

专用数据格式