Skip to content

Commit 0e504d9

Browse files
committed
Add alternatives to static methods
1 parent e941469 commit 0e504d9

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

tests/AggregationBlogPost/FuelExample1Test.php

+29
Original file line numberDiff line numberDiff line change
@@ -598,4 +598,33 @@ public function testExtractExpressionsExtractedDurationComputation(): void
598598
),
599599
);
600600
}
601+
602+
public function testFirstClassCallableSyntax(): void
603+
{
604+
$reportDate = Expression::dateFieldPath('reportDate');
605+
$price = Expression::doubleFieldPath('price');
606+
$fuelType = Expression::fieldPath('fuelType');
607+
$brand = Expression::fieldPath('station.brand');
608+
609+
$group = Stage::group(...);
610+
$year = Expression::year(...);
611+
$month = Expression::month(...);
612+
$min = Accumulator::min(...);
613+
$max = Accumulator::max(...);
614+
$avg = Accumulator::avg(...);
615+
$sum = Accumulator::sum(...);
616+
617+
$group(
618+
_id: object(
619+
year: $year($reportDate),
620+
month: $month($reportDate),
621+
fuelType: $fuelType,
622+
brand: $brand,
623+
),
624+
lowest: $min($price),
625+
highest: $max($price),
626+
average: $avg($price),
627+
count: $sum(1),
628+
);
629+
}
601630
}

tests/AggregationBlogPost/article.md

+84
Original file line numberDiff line numberDiff line change
@@ -718,3 +718,87 @@ regression should we make any changes to the generator, and it allows us to use
718718
the builder and feel what it's like. Ultimately, we love to add this builder
719719
code to the server documentation, similar to how we add other language-specific
720720
code snippets, but we're not quite there yet.
721+
722+
## Builder Syntax - Static Methods or Functions?
723+
724+
I've mentioned before that the builder uses static methods because of naming
725+
conflicts. It really comes down to a few names, for example the `$match` stage
726+
and `$and` or `$switch` operators. While PHP allows us to use reserved keywords
727+
as names for methods in a class, they are not allowed for function names. We
728+
have considered using suffixes for namespaced functions:
729+
730+
```php
731+
function andQuery(...) {}
732+
function matchStage(...) {}
733+
function switchOperator(...) {}
734+
```
735+
736+
Adding a suffix to every stage and operator doesn't really reduce verbosity, so
737+
we decided against it. Another option was to use an underscore prefix for all
738+
reserved names:
739+
740+
```php
741+
function _and(...) {}
742+
function _match(...) {}
743+
function _switch(...) {}
744+
```
745+
746+
We also decided against this option, partly because the underscore marks (or at
747+
least used to mark) private functions or methods, but also because the
748+
underscore would break alphabetical sorting in code completion.
749+
750+
A less-than-serious approach was to use emojis, which I learned was valid in
751+
PHP:
752+
753+
```php
754+
function 🔍and(...) {}
755+
function 💲match(...) {}
756+
```
757+
758+
In all seriousness, there are alternatives if you dislike the static methods.
759+
PHP's
760+
[first class callable syntax](https://www.php.net/manual/en/functions.first_class_callable_syntax.php)
761+
allows you to create a closure from an existing method and store it in a
762+
variable to later invoke the closure:
763+
764+
```php
765+
$reportDate = Expression::dateFieldPath('reportDate');
766+
$price = Expression::doubleFieldPath('price');
767+
$fuelType = Expression::fieldPath('fuelType');
768+
$brand = Expression::fieldPath('station.brand');
769+
770+
$group = Stage::group(...);
771+
$year = Expression::year(...);
772+
$month = Expression::month(...);
773+
$min = Accumulator::min(...);
774+
$max = Accumulator::max(...);
775+
$avg = Accumulator::avg(...);
776+
$sum = Accumulator::sum(...);
777+
778+
$group(
779+
_id: object(
780+
year: $year($reportDate),
781+
month: $month($reportDate),
782+
fuelType: $fuelType,
783+
brand: $brand,
784+
),
785+
lowest: $min($price),
786+
highest: $max($price),
787+
average: $avg($price),
788+
count: $sum(1),
789+
);
790+
```
791+
792+
Again, PHP's use of `$` to mark variables plays nice with aggregation pipeline
793+
using it for stages and operators. We have considered adding a method to each
794+
factory class that would return an array of closures to make this easier:
795+
796+
```php
797+
['year' => $year, 'month' => $month] = Accumulator::accumulators();
798+
799+
// Alternatively, if you want to use all accumulators as variables:
800+
extract(Accumulator::accumulators());
801+
```
802+
803+
We have not implemented this for now, but if you prefer this syntax to static
804+
methods, or if you have alternative suggestions, please let us know about them!

0 commit comments

Comments
 (0)