Table of Contents
15. Intersection Types — Requiring Multiple Shapes at Once
Intersection types let us declare that
a value must satisfy all of several types at the same time.
They are the opposite of union types:
instead of “one of these”,
intersection types mean “all of these”.
They reflect a broader shift in modern PHP:
→ contracts should be precise, not permissive.
1. What Intersection Types Are
An intersection type requires that a value implement every listed type:
function handle(Logger&Stringable $value) { // $value must be both Logger and Stringable }
This is not flexibility.
This is precision.
2. Why Modern PHP Uses Them
Intersection types give us:
- stronger contracts
- clearer expectations
- safer polymorphism
- better support for composition
- more expressive type boundaries
They let us describe values that must satisfy multiple roles at once.
3. The Mental Model
An intersection type is a contract made of multiple obligations.
It’s not about “allowing more”.
It’s about “requiring more”.
The key idea:
- Use intersection types when
a value must fulfill multiple interfaces simultaneously.
Not optionally. Not sometimes. Always.
4. A Simple Example
Imagine a value that must log messages and be converted to a string:
Without intersection types:
/** * @param Logger&Stringable $value */ function handle($value) { /* ... */ }
The contract is hidden in a comment.
With intersection types:
function handle(Logger&Stringable $value) { /* ... */ }
The meaning is visible. The requirement is explicit.
5. When to Use Intersection Types
Use them when:
- a value must satisfy multiple interfaces
- the combination expresses a meaningful role
- the contract is stable and intentional
- we want to avoid runtime checks
- we want clarity at the boundary
Intersection types shine in
middleware, pipelines, adapters,
and behavioral composition.
6. When Not to Use Intersection Types
Avoid them when:
- the combination is accidental, not meaningful
- the value could be normalized earlier
- the contract is unstable or evolving
- the intersection hides unclear design
- the types represent conflicting responsibilities
Intersection types are for precise contracts,
not flexible inputs.
When AI Gets This Wrong
AI often invents intersection types that don’t make sense, or combines interfaces that have no meaningful relationship. Sometimes it uses intersections where a simple interface would be clearer, or mixes union and intersection types in ways that confuse the contract.
Our mental model helps us see when an intersection expresses a real obligation
—
and when AI is using it simply because it “looks expressive”.
Summary
Intersection types let us express precise, multi‑role contracts.
They require that a value satisfy all listed types,
making boundaries clearer and safer.
Once we internalize this,
we can immediately see when AI‑generated code:
- invents meaningless intersections
- mixes incompatible interfaces
- uses intersections to avoid design decisions
- or misses opportunities to express real obligations
Intersection types are a small feature
— but they teach us
how modern PHP wants to express precision and intention in its contracts.
