|
| 1 | +# Variadic Arguments Pattern for Required Parameters |
| 2 | + |
| 3 | +[TOC] |
| 4 | + |
| 5 | +Proposed by: @norberttech |
| 6 | +Date: 2026-03-02 |
| 7 | + |
| 8 | +## Context |
| 9 | +--- |
| 10 | + |
| 11 | +Several Flow PHP methods accept multiple arguments where at least one is required. Examples include: |
| 12 | +- `DataFrame::partitionBy()` |
| 13 | +- `Rows::partitionBy()` |
| 14 | +- `Window::partitionBy()` |
| 15 | +- Type comparison methods |
| 16 | + |
| 17 | +A proposal was made to simplify the API signatures from: |
| 18 | + |
| 19 | +```php |
| 20 | +public function partitionBy(string|Reference $entry, string|Reference ...$entries) : self |
| 21 | +``` |
| 22 | + |
| 23 | +To: |
| 24 | + |
| 25 | +```php |
| 26 | +public function partitionBy(string|Reference ...$entries) : self |
| 27 | +``` |
| 28 | + |
| 29 | +The rationale for the proposal was to reduce array operations like `array_unshift()` used internally to merge the first required argument with the variadic rest. |
| 30 | + |
| 31 | +## Decision |
| 32 | +--- |
| 33 | + |
| 34 | +**Keep the explicit first argument pattern** |
| 35 | + |
| 36 | +Methods that require at least one argument should use the signature pattern: |
| 37 | + |
| 38 | +```php |
| 39 | +public function method(Type $first, Type ...$rest) : ReturnType |
| 40 | +``` |
| 41 | + |
| 42 | +Rather than: |
| 43 | + |
| 44 | +```php |
| 45 | +public function method(Type ...$args) : ReturnType |
| 46 | +``` |
| 47 | + |
| 48 | +## Pros & Cons |
| 49 | +--- |
| 50 | + |
| 51 | +**Advantages of the chosen pattern:** |
| 52 | + |
| 53 | +- **Compile-time enforcement**: PHP enforces at least one argument at the language level |
| 54 | +- **Static analysis support**: PHPStan, Psalm, and IDEs immediately understand the constraint |
| 55 | +- **Better developer experience**: The method signature clearly communicates the requirement without needing to read documentation or encounter runtime exceptions |
| 56 | +- **Fail-fast principle**: Errors are caught before execution, not during |
| 57 | + |
| 58 | +**Disadvantages:** |
| 59 | + |
| 60 | +- Internal implementation requires merging arguments: `array_unshift($rest, $first)` |
| 61 | +- Slightly more verbose method signatures |
| 62 | +- Minor performance overhead from array operations (negligible in practice) |
| 63 | + |
| 64 | +## Alternatives Considered |
| 65 | +--- |
| 66 | + |
| 67 | +### 1. Pure variadic with runtime validation |
| 68 | + |
| 69 | +```php |
| 70 | +public function partitionBy(string|Reference ...$entries) : self |
| 71 | +{ |
| 72 | + if ([] === $entries) { |
| 73 | + throw new InvalidArgumentException('At least one entry is required.'); |
| 74 | + } |
| 75 | + // ... |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +**Rejected because:** Developers only discover the constraint at runtime, leading to worse developer experience. |
| 80 | + |
| 81 | +### 2. Validation in the References class |
| 82 | + |
| 83 | +```php |
| 84 | +final class References |
| 85 | +{ |
| 86 | + public function __construct(string|Reference ...$references) |
| 87 | + { |
| 88 | + if ([] === $references) { |
| 89 | + throw new InvalidArgumentException('References cannot be empty.'); |
| 90 | + } |
| 91 | + // ... |
| 92 | + } |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +**Rejected because:** While this centralizes validation, it still defers the error to runtime. The explicit first argument pattern catches errors earlier in the development cycle. |
| 97 | + |
| 98 | +## Links and References |
| 99 | +--- |
| 100 | + |
| 101 | +- [GitHub Issue #2236](https://github.com/flow-php/flow/issues/2236) - Original proposal discussion |
0 commit comments