When a class implements an interface, that interface has to exist, or PHP stops with a fatal error. That's a problem for libraries that want to integrate with another library without requiring it. This RFC from Juris Evertovskis proposed letting you put a ? before an interface name: if the interface exists, the class implements it, and if not, PHP skips it. It was declined.
The problem today
Libraries work around this in a few ways. Some wrap the whole class in an if, some define empty stand-in interfaces, and some use class aliases. The RFC points to examples in Symfony, Laravel, WordPress and Carbon.
Here is the if approach, trimmed from the RFC:
if (interface_exists(LaravelExpression::class)) { class BaseExpression implements \Stringable, LaravelExpression { use BaseExpressionImplementation; } } else { class BaseExpression implements \Stringable { use BaseExpressionImplementation; } }
With the RFC, that becomes a single class:
class BaseExpression implements \Stringable, ?LaravelExpression { // The actual implementation }
How it works
- The
?applies only to the name right after it, and you can mix required and optional interfaces in any order. - It works in an interface's
extendslist too. - PHP checks whether the interface exists when the class is declared, and it still tries the autoloader first.
- If the interface exists, all the normal rules apply, so your class must still implement every method the interface requires.
- A class only counts as the types it actually implements. Passing it where a missing interface is expected throws a
TypeError. - Reflection lists only the interfaces the class actually implements.
What it means for existing code
Nothing breaks. A ? in an interface list isn't valid PHP today, so no working code uses it.
The vote
The vote failed 15 to 19, well short of the two-thirds majority it needed. The poll offered only Yes and No, and voting closed on March 29, 2025.