ホームページ  >  記事  >  バックエンド開発  >  PHP の命名制限を克服して MongoDB オペレーターをモデル化する方法

PHP の命名制限を克服して MongoDB オペレーターをモデル化する方法

DDD
DDD転載
2023-10-18 10:56:00794ブラウズ

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"
        }
    }
])

ドルの接頭辞が付いた各キーは、ファクトリ メソッドを提供する演算子です。

名前空間関数

最も明白な解決策は、名前空間関数を作成することです (例: MongoDBOperatoreqof$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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はJérôme TAMARELLEで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。