rfc:optional-interfaces

PHP RFC: Optional Interfaces

Introduction

PHP's implements keyword allows classes to declare that they implement one or more interfaces. This mechanism is strict: the specified interfaces must exist at runtime. While this strictness is usually beneficial, it can create challenges when developing libraries that need to interoperate with other optional libraries or different versions of libraries and when creating projects that need to be compatible with multiple PHP versions and usable with or without some PHP extensions.

In such scenarios developers resort to workarounds like

These solutions introduce complexity and a maintenance burden. The conditional declarations may sometimes confuse IDEs and static analysis tools that pick up the multiple definitions. If an optional interface is mocked by a dummy, the implementing class contains no indication of that and misleads the reader into thinking that an actual interface with that name is defined in a meaningful way.

Proposal

By prefixing an interface name with ?, a class can optionally implement an interface. If the interface exists, the class will implement it; otherwise, the declaration will be ignored without causing an error.

This allows the developer to clearly announce that the class is interoperable with an interface, but does not require the interface per se.

Example 1: Implementing an interface if it exists

namespace MyNamespace;
 
use ExternalNamespace\TheInterface;
 
class MyClass implements ?TheInterface
{
    // ...
}

If \ExternalNamespace\TheInterface exists, MyClass will implement it. It will behave as if the class was declared as class MyClass implements TheInterface.

If it doesn't exist, MyClass will work as if it was declared without implements ?TheInterface.

Example 2: Optional interfaces in a list of interfaces

Optional interfaces can appear on an interface list together with required interfaces in any order. The ? applies only to the name directly following the token.

class MyClass1 implements A, B, ?C, ?D {}
class MyClass2 implements ?C, ?D, A, B {}
class MyClass3 implements A, ?C, ?D, B {}
class MyClass4 implements ?C, A, B, ?D {}

All of these classes implement and require interfaces A and B while the interfaces C and D will only be implemented if they exist.

Example 3: Extending optional interfaces

An interface can also be optional when it's in an extends list of another interface. The list of extandable interface names works just like the implements list for classes.

interface MyInterface extends RequiredInterface, ?OptionalInterface {}

Backward Incompatible Changes

None.

Classes that do not use the ? token in the interface list will function as before. Before this RFC the ? token in interface lists is not valid, therefore a runnable code that would be affected does not exist.

Proposed PHP Version(s)

Next PHP 8.x.

RFC Impact

To Opcache

It is necessary to develop RFC's with opcache in mind, since opcache is a core extension distributed with PHP.
Please explain how you have verified your RFC's compatibility with opcache.

I have not verified the compatibility with the opcache yet.

To Reflection API

Currently this RFC does not add the optionality information in the Reflection API.

Proposed Voting Choices

Include these so readers know where you are heading and can discuss the proposed voting options.

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature
  4. a link to the language specification section (if any)

References

Rejected Features

Keep this updated with features that were discussed on the mail lists.

rfc/optional-interfaces.txt · Last modified: 2024/12/28 21:14 by tontonsb