This RFC proposes the addition of a syntax that allows closures to declare one or more interfaces they implement. This would provide developers with a more explicit and type-safe way to define and interact with closures in PHP. The proposed syntax is as follows:
$f = function ($a) implements FooInterface { ... };
The current version of PHP allows closures to be used as a convenient way to define anonymous functions. However, the language does not offer a way to explicitly define the interfaces that a closure implements, which can lead to less clear and less type-safe code. The proposed change would allow closures to declare one or more interfaces they implement, providing a more robust and explicit way to interact with closures.
Since closures implement only one __invoke()
method, the interfaces listed when declaring the closure should all declare one single compatible __invoke()
method.
The proposed syntax adds an implements
keyword followed by one or more interface names to the closure declaration. This addition can be combined with optional return types and the short closure syntax.
$add = function (int $a, int $b) use ($c): int implements AddInterface { return $a + $b + $c; };
$process = function ($input) use ($config): Result implements ProcessorInterface, ValidatorInterface { // ... };
$square = fn (int $x): int implements SquarerInterface => $x * $x;
Technically, closures are instances of the native Closure
class. In order to bind the listed interfaces as proposed by this RFC, closures that implement an interface would have to be instances of a child class of the Closure
class.
Conceptually:
$f = function ($a) implements FooInterface { ... };
Should be equivalent to:
$f = new class() extends Closure implements FooInterface { public function __invoke($a) { ... } };
This RFC does not propose to make this code valid.
This snippet is here to illustrate the possible side-effects of adding an interface to a closure as far as reflection is concerned.
Introducing the ability to declare interfaces for closures would provide several benefits:
Thanks to this feature, it is expected that code authors would shift from type-hinting for Closure
to type-hinting for interfaces they could leverage for the purpose of better type safety:
Before:
class Example { /** * @param Closure(Input):Result $processor */ function setProcessor(Closure $processor) { // ... } } (new Example)->setProcessor(fn ($input) => $result);
After:
interface ProcessorInterface { public function __invoke(Input $input): Result; } class Example { function setProcessor(ProcessorInterface $processor) { // ... } } (new Example)->setProcessor(fn ($input) implements ProcessorInterface => $result);
The proposed change would be fully backward compatible, as it adds a new feature without affecting existing functionality.
castTo()
method that'd allow turning a Closure instance into an instance of another single-method interface. See https://wiki.php.net/rfc/allow_casting_closures_into_single-method_interface_implementationsThis RFC targets PHP version 8.3.
The vote will require a 2/3 majority to be accepted. Voting will start on [Vote start date] and end on [Vote end date].