The OneOfSchema validates a value against several schemas and requires exactly one to match: parsing fails when no schema matches, and also when two or more match. It covers the JSON Schema oneOf keyword.
use Chubbyphp\Parsing\Parser;
$p = new Parser();
$schema = $p->oneOf([$p->string(), $p->int()]);
$data = $schema->parse('test'); // Returns: 'test' (only the string schema matches)
$data = $schema->parse(42); // Returns: 42 (only the int schema matches)
$data = $schema->parse(1.5); // Throws error (no schema matches, both errors reported)
$schema = $p->oneOf([$p->int(), $p->float()]);
$data = $schema->parse(1); // Throws error (both schemas match)- Every schema is evaluated against the original input — unlike UnionSchema, which stops at the first success
- Exactly one match: that schema's output is returned — exactly-one means the applied coercion is unambiguous, so unlike AllOfSchema the output is kept
- No match: every schema's errors are reported, in schema order
- Two or more matches: a single
oneOf.multipleMatcherror reports the matching schema indexes — the schemas succeeded, so there are no inner errors to report
| Schema | Matches required | Evaluation |
|---|---|---|
union() |
at least one | stops at first success |
oneOf() |
exactly one | always evaluates all schemas |
discriminatedUnion() |
the one selected by the discriminator field | evaluates only the selected schema |
Prefer discriminatedUnion() when a discriminator field exists — it is faster and produces better errors. oneOf() is for genuinely overlapping schemas where exclusivity itself is the constraint, and for compiling JSON Schema documents that use oneOf without a discriminator.
- Overlapping schemas are a modeling smell:
oneOf([int(), float()])fails for1because both match. If "either is fine" is meant, that isunion(), notoneOf(). - A matched
nullable()branch may outputnull:oneOf([$p->string()->nullable(), $p->int()])parsesnulltonullvia the first schema — anulloutput is not a failed match. - Schemas that cannot fail: a subschema with
catch()ordefault()may always succeed and then causesoneOf.multipleMatchas soon as any other schema also matches.
| Code | Description |
|---|---|
oneOf.multipleMatch |
Input matches more than one schema |
When no schema matches, the subschemas' own errors propagate unchanged.