respect-validation/docs/validators/ShortCircuit.md
Henrique Moody b701fac656
Create ShortCircuit validator and ShortCircuitable interface
This commit introduces a mechanism for validators to return early once
the validation outcome is determined, rather than evaluating all child
validators.

The ShortCircuit validator evaluates validators sequentially and stops
at the first failure, similar to how PHP's && operator works. This is
useful when later validators depend on earlier ones passing, or when
you want only the first error message.

The ShortCircuitCapable interface allows composite validators (AllOf,
AnyOf, OneOf, NoneOf, Each, All) to implement their own short-circuit
logic.

Why "ShortCircuit" instead of "FailFast":

The name "FailFast" was initially considered but proved misleading.
While AllOf stops on failure (fail fast), AnyOf stops on success
(succeed fast), and OneOf stops on the second success. The common
behavior is not about failing quickly, but about returning as soon as
the outcome is determined—which is exactly what short-circuit
evaluation means. This terminology is familiar to developers from
boolean operators (&& and ||), making the behavior immediately
understandable.

Co-authored-by: Alexandre Gomes Gaigalas <alganet@gmail.com>
Assisted-by: Claude Code (Opus 4.5)
2026-02-05 17:32:42 +01:00

2.8 KiB

ShortCircuit

  • ShortCircuit()
  • ShortCircuit(Validator ...$validators)

Validates the input against a series of validators, stopping at the first failure.

Like PHP's && operator, it uses short-circuit evaluation: once the outcome is determined, remaining validators are skipped. Unlike AllOf, which evaluates all validators and collects all failures, ShortCircuit returns immediately.

v::shortCircuit(v::intVal(), v::positive())->assert(15);
// Validation passes successfully

This is useful when:

  • You want only the first error message instead of all of them
  • Later validators depend on earlier ones passing (e.g., checking a format before checking a value)
  • You want to avoid unnecessary validation work

This validator is particularly useful in combination with Factory when later validations depend on earlier results. For example, validating a subdivision code that depends on a valid country code:

$validator = v::shortCircuit(
    v::key('countryCode', v::countryCode()),
    v::factory(static fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countryCode']))),
);

$validator->assert([]);
// → `.countryCode` must be present

$validator->assert(['countryCode' => 'US']);
// → `.subdivisionCode` must be present

$validator->assert(['countryCode' => 'US', 'subdivisionCode' => 'ZZ']);
// → `.subdivisionCode` must be a subdivision code of United States

$validator->assert(['countryCode' => 'US', 'subdivisionCode' => 'CA']);
// Validation passes successfully

Because SubdivisionCode requires a valid country code, it only makes sense to validate the subdivision after the country code passes. You could achieve this with When, but you would have to repeat v::key('countryCode', v::countryCode()) twice.

Note

The check() method in ValidatorBuilder uses ShortCircuit internally to short-circuit the entire validation chain. Use ShortCircuit directly when you need fine-grained control over which specific group of validators should fail fast, while letting the rest of the validation continue collecting errors via assert().

Templates

This validator does not have templates of its own. It returns the result of the first failing validator, or the result of the last validator when all pass.

Categorization

  • Composite
  • Conditions
  • Nesting

Changelog

Version Description
3.0.0 Created

See Also