Skip to content
Search

Variadic Arguments Pattern for Required Parameters

Proposed by: @norberttech Date: 2026-03-02

Context


Several Flow PHP methods accept multiple arguments, and at least one argument is required. Examples:

  • DataFrame::partitionBy()
  • Rows::partitionBy()
  • Window::partitionBy()
  • Type comparison methods

A proposal wanted to make the API signatures simpler, from:

public function partitionBy(string|Reference $column, string|Reference ...$columns) : self

To:

public function partitionBy(string|Reference ...$columns) : self

The reason for the proposal was fewer array operations, such as the internal array_unshift() that merges the first required argument with the variadic rest.

Decision


Keep the explicit first argument pattern.

Methods that require at least one argument must use this signature pattern:

public function method(Type $first, Type ...$rest) : ReturnType

Not:

public function method(Type ...$args) : ReturnType

Pros & Cons


Advantages of the chosen pattern:

  • Compile-time enforcement: PHP enforces at least one argument at the language level
  • Static analysis support: PHPStan, Psalm, and IDEs understand the constraint immediately
  • Better developer experience: the method signature shows the requirement clearly. The developer does not have to read documentation or get runtime exceptions
  • Fail-fast principle: errors are found before execution, not during execution

Disadvantages:

  • The internal implementation must merge arguments: array_unshift($rest, $first)
  • Slightly longer method signatures
  • A small performance overhead from array operations (negligible in practice)

Alternatives Considered


1. Pure variadic with runtime validation

public function partitionBy(string|Reference ...$columns) : self
{
    if ([] === $columns) {
        throw new InvalidArgumentException('At least one column is required.');
    }
    // ...
}

Rejected because: developers find the constraint only at runtime. The developer experience is worse.

2. Validation in the References class

final class References
{
    public function __construct(string|Reference ...$references)
    {
        if ([] === $references) {
            throw new InvalidArgumentException('References cannot be empty.');
        }
        // ...
    }
}

Rejected because: this puts the validation in one place, but the error still happens only at runtime. The explicit first argument pattern finds errors earlier in the development cycle.

Links and References


Found a typo or an outdated section? Edit this page on GitHub


Contributors

Built in the open.

Join us on GitHub
scroll back to top