登录  /  注册

如何克服PHP的命名限制来建模MongoDB运算符

DDD
发布: 2023-10-18 10:56:00
转载
666人浏览过

mongodb 提供了包括 php 在内的各种语言的驱动程序。为了简化在 php 中创建聚合管道的过程,我们需要将所有阶段和运算符建模为可以组合的函数。

聚合管道是“阶段”文档的列表。我们将举一个使用 进行查询$match和连接的示例$lookup:

db.orders.aggregate([
    {
        $match: {
            $or: [
                { status: "shipped" },
                { created_at: { $gte: ISODate("2023-01-01T00:00:00Z") } }
            ]
        }
    },
    {
        $lookup: {
            from: "inventory",
            localField: "product_id",
            foreignField: "product_id",
            as: "inventory_docs"
        }
    }
])
登录后复制

每个带有美元前缀的键都是我们要为其提供工厂方法的运算符。

命名空间函数

最明显的解决方案是创建命名空间函数,例如:MongoDB\Operator\eqof$eq运算符。

namespace MongoDB\Operator;
function eq(mixed $value): array {
    return ['$eq' => $value];
}
function lookup(string $from, string $localField, string $foreignField, string $as): array {
    return ['$lookup' => [
        'from' => $from,
        'localField' => $localField,
        'foreignField' => $foreignField,
        'as' => $as,
    ]];
}
登录后复制

使用带有命名参数的函数,管道将用 PHP 编写:

pipeline(
    match(
        or(
            query(status: eq('shipped')),
            query(date: gte(new UTCDateTime())),
        ),
    ),
    lookup(from: 'inventory', localField: 'product_id', foreignField: 'product_id', as: 'inventory_docs'),
);
登录后复制

但是,某些运算符名称与PHP 中的保留关键字冲突。我们不能创建具有以下名称的函数(全局或命名空间):

and,

or,

match,

unset,

set,

为函数名添加后缀

为了避免保留名称的问题,我们可以在函数名称中添加前缀或后缀。

以运算符类型作为后缀:

function andQuery(...) { /* ... */ }
function matchStage(...) { /* ... */ }
登录后复制

带下划线:

function _and(...) { /* ... */ }
function _match(...) { /* ... */ }
登录后复制

或者使用表情符号。漂亮,但不实用:

function ?and(...) { /* ... */ }
function ?match(...) { /* ... */ }
登录后复制

静态类方法

碰巧的是,方法名称的保留关键字列表较短。我们可以在类上创建静态方法。

final class Stage {
    public static function lookup(...) { /* ... */ }
    public static function match(...) { /* ... */ }
}
final class Query {
    public static function and(...) { /* ... */ }
    public static function eq(...) { /* ... */ }
}
登录后复制

字写得有点长了,不过还是可读的。

new Pipeline(
    Stage::match(
        Query::or(
            Query::query(status: Query::eq('shipped')),
            Query::query(date: Query::gte(new UTCDateTime())),
        ),
    ),
    Stage::lookup(from: 'inventory', localField: 'product_id', foreignField: 'product_id', as: 'inventory_docs'),
);
登录后复制

为了防止任何人创建此类的实例,我们可以将构造函数设为私有。

final class Operator {
    // ...
    private function __construct() {} // This constructor cannot be called 
}
登录后复制

我们也可以使用enum不带外壳的。Enum 接受静态方法并且不能实例化。

enum Query {
    public static function and() { /* ... */ }
    public static function eq() { /* ... */ }
}
登录后复制

类和枚举静态方法都可以以相同的方式调用。

变量中的闭包

由于找不到理想的解决方案,我们开始热衷于不太可能的解决方案。

如果我们想要一个看起来与 MongoDB 语法非常相似且没有名称限制的简短语法,那么我们就会想到使用变量来存储闭包。请注意,这(...)是PHP 8.1 中创建闭包的新语法。

$eq = Operator::eq(...);
$and = Operator::and(...);
登录后复制

$PHP 使用美元符号作为变量前缀,MongoDB 使用相同的运算符作为前缀。

pipeline(
    $match(
        $or(
            $query(status: $eq('shipped')),
            $query(date: $gte(new UTCDateTime())),
        ),
    ),
    $lookup(from: 'inventory', localField: 'product_id', foreignField: 'product_id', as: 'inventory_docs'),
);
登录后复制

库可以将这些闭包作为数组提供。

enum Query {
    public static function and(array ...$queries) { /* ... */ }
    public static function eq(mixed $value) { /* ... */ }
    public static function query(mixed ...$query) { /* ... */ }
    /** @return array{and:callable,eq:callable,query:callable} */
    public static function functions(): array {
        return [
            'and' => self::and(...),
            'eq' => self::eq(...),
            'query' => self::query(...),
        ];
    }
}
登录后复制

获取所有变量的语法有点冗长,但仍然可读。

['and' => $and, 'eq' => $eq, 'query' => $query] = Query::functions();
登录后复制

extract我们可以使用 Laravel 中经常使用但 PHPStorm 和静态分析工具非常讨厌的神奇功能将所有变量导入到当前作用域中。

extract(Query::functions());
var_dump($and(
    $query(foo: $eq(5)),
    $query(bar: $eq(10))
));
// INFO: MixedFunctionCall - Cannot call function on mixed
登录后复制

结论

正如您所看到的,在使用保留关键字时,PHP 中的函数命名并不那么简单。

以上就是如何克服PHP的命名限制来建模MongoDB运算符的详细内容,更多请关注php中文网其它相关文章!

智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
关于CSS思维导图的课件在哪? 课件
凡人来自于2024-04-16 10:10:18
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2024 //m.sbmmt.com/ All Rights Reserved | php.cn | 湘ICP备2023035733号