MongoDB bietet Treiber für verschiedene Sprachen, einschließlich PHP. Um den Prozess der Erstellung von Aggregationspipelines in PHP zu vereinfachen, müssen wir alle Phasen und Operatoren als zusammensetzbare Funktionen modellieren.
Aggregationspipeline ist eine Liste von „Stufen“-Dokumenten. Wir geben ein Beispiel für die Abfrage von $match und die Verknüpfung mit $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" } } ])
Jeder Schlüssel mit einem Dollar-Präfix ist ein Operator, für den wir eine Factory-Methode bereitstellen möchten.
Namespace-Funktionen
Die naheliegendste Lösung besteht darin, eine Namespace-Funktion zu erstellen, zum Beispiel: MongoDBOperatoreqof$eq-Operator.
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, ]]; }
Bei Verwendung von Funktionen mit benannten Parametern werden Pipes in PHP geschrieben:
pipeline( match( or( query(status: eq('shipped')), query(date: gte(new UTCDateTime())), ), ), lookup(from: 'inventory', localField: 'product_id', foreignField: 'product_id', as: 'inventory_docs'), );
Allerdings stehen einige Operatornamen im Konflikt mit reservierten Schlüsselwörtern in PHP. Wir können keine Funktionen (global oder Namespace) mit den folgenden Namen erstellen:
and,
or,
match,
unset,
set,
Suffix zum Funktionsnamen hinzufügen
Um das Problem der Namensspeicherung zu vermeiden, können wir dem Funktionsnamen ein Präfix oder Suffix hinzufügen.
Mit dem Operatortyp angehängt:
function andQuery(...) { /* ... */ } function matchStage(...) { /* ... */ }
Unterstrichen:
function _and(...) { /* ... */ } function _match(...) { /* ... */ }
Oder verwenden Sie Emoticons. Schön, aber unpraktisch:
function ?and(...) { /* ... */ } function ?match(...) { /* ... */ }
Statische Klassenmethode
Zufällig ist die Liste der reservierten Schlüsselwörter für Methodennamen kürzer. Wir können statische Methoden für Klassen erstellen.
final class Stage { public static function lookup(...) { /* ... */ } public static function match(...) { /* ... */ } } final class Query { public static function and(...) { /* ... */ } public static function eq(...) { /* ... */ } }
Der Text ist etwas lang, aber dennoch lesbar.
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'), );
Um zu verhindern, dass jemand eine Instanz dieser Klasse erstellt, können wir den Konstruktor privat machen.
final class Operator { // ... private function __construct() {} // This constructor cannot be called }
Wir können enum auch ohne Shell verwenden. Enum akzeptiert statische Methoden und kann nicht instanziiert werden.
enum Query { public static function and() { /* ... */ } public static function eq() { /* ... */ } }
Statische Klassen- und Aufzählungsmethoden können auf die gleiche Weise aufgerufen werden.
Abschlüsse in Variablen
Da wir keine ideale Lösung finden konnten, begannen wir, uns für unwahrscheinliche Lösungen zu begeistern.
Wenn wir eine kurze Syntax wünschen, die der MongoDB-Syntax ohne Namensbeschränkungen sehr ähnlich sieht, dann würden wir über die Verwendung von Variablen zum Speichern von Abschlüssen nachdenken. Beachten Sie, dass dies (...) die neue Syntax zum Erstellen von Abschlüssen in PHP 8.1 ist.
$eq = Operator::eq(...); $and = Operator::and(...);
$PHP verwendet ein Dollarzeichen für variable Präfixe und MongoDB verwendet denselben Operator für Präfixe.
pipeline( $match( $or( $query(status: $eq('shipped')), $query(date: $gte(new UTCDateTime())), ), ), $lookup(from: 'inventory', localField: 'product_id', foreignField: 'product_id', as: 'inventory_docs'), );
Die Bibliothek kann diese Abschlüsse als Arrays bereitstellen.
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(...), ]; } }
Die Syntax zum Abrufen aller Variablen ist etwas ausführlich, aber dennoch lesbar.
['and' => $and, 'eq' => $eq, 'query' => $query] = Query::functions();
extrahieren Wir können alle Variablen in den aktuellen Bereich importieren, indem wir eine magische Funktion in Laravel verwenden, die oft verwendet wird, aber von PHPStorm und statischen Analysetools gehasst wird.
extract(Query::functions()); var_dump($and( $query(foo: $eq(5)), $query(bar: $eq(10)) )); // INFO: MixedFunctionCall - Cannot call function on mixed
Fazit
Wie Sie sehen, ist die Benennung von Funktionen in PHP nicht so einfach, wenn reservierte Schlüsselwörter verwendet werden.
Das obige ist der detaillierte Inhalt vonSo überwinden Sie die Namensbeschränkungen von PHP zur Modellierung von MongoDB-Operatoren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!