>백엔드 개발 >PHP 튜토리얼 >MongoDB 연산자를 모델링하기 위해 PHP의 명명 제한을 극복하는 방법

MongoDB 연산자를 모델링하기 위해 PHP의 명명 제한을 극복하는 방법

DDD
DDD앞으로
2023-10-18 10:56:00804검색

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,

또는

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 자주 사용되지만 PHPStorm 및 정적 분석 도구에서는 싫어하는 Laravel의 마법 같은 기능을 사용하여 모든 변수를 현재 범위로 가져올 수 있습니다.

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

결론

보시다시피 PHP에서 예약어를 사용하면 함수 이름 지정이 그리 간단하지 않습니다.

위 내용은 MongoDB 연산자를 모델링하기 위해 PHP의 명명 제한을 극복하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 Jérôme TAMARELLE에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제