On Sunday, 29 March 2026 at 22:45, Osama Aldemeery <aldemeery@gmail.com> wrote:
Hi all,
I'd like to propose an Invokable interface, the Stringable equivalent for __invoke().
The idea has come up a few times over the years (most recently in the PR #15492 discussion, where Gina suggested this exact approach) but never had a concrete implementation.
I've put one together: Add `Invokable` interface by aldemeery · Pull Request #21574 · php/php-src · GitHub
It follows the Stringable pattern: auto-implemented for any class defining __invoke(), explicitly implementable with enforcement, and covariant to callable in return type checks.
I'm working on a formal RFC and would love feedback before posting it.
I'd also like to request wiki karma to create the RFC page — my wiki username is aldemeery
I already replied on the PR, but I am very much *not* in favour of this proposal.
My comment in PR #15492 [1] specifically says that we don't have such an interface, and I don't want to add duck typing as this goes against PHP's nominal typing system.
The discussion around such an interface happened in PR #18161 [2].
However, Tim noted that we cannot have an interface the defines the signature of __invoke().
And then Ilija suggested a marker interface similar to Throwabale.
In the year since this discussion has happened I've had time to think and the reason I never even attempted to move this forward is that this is, IMHO, repeating the same mistake of `Stringable`.
The only reason for `Stringable` to exists is that `strict_types` exists, and when enabled prevents objects with a `__toString()` method to be passed to `string` types.
This causes nonsensical design choices of "should I mark my parameters as `string|Stringable` or not" when it should just always be `string` and let the engine do the type juggling.
The proposal of adding an `Invokable` interfaces reproduces this exact same mistake.
One shouldn't care that the callable is an object with an invoke method? Why could it not be a callable array or be a callable string?
As the consumer of such an argument the representation of a callable shouldn't matter.
The main argument seems to be that the callable type cannot be used on property types.
There are 2 reasons why this is the case.
The one most people know is that string/array callables is because there are scope visibility implications.
(See Online PHP editor | output for hCpiG for an example.)
However, the **primary** reason is because of partially supported callables that have been deprecated in PHP 8.2. [3]
Those partially supported callables don't just depend on *where* they are created but also where they are *used*.
When those partially supported callables are removed in PHP 9, it seems very feasible to allow `callable` to be used as a property type.
The mechanism to do so would be to *effectively* convert any "legacy" (array, string, object with __invoke methods) callables into a `Closure` object during the type check.
This would remove any scope visibility issues from callables created within methods.
(As an aside I firmly believe this behaviour would reduce the engine complexity around callables)
Moreover, I don't believe that a magic interface that does effectively nothing is good language design,
and that this is trying to fix a "problem" in a way that is going to cause more problems down the line rather than wait for the proper solution of fixing the `callable` type.
Similarly to how I feel about the introduction of `Stringable`, where the proper solution IMHO is to unify PHP's typing modes. [4]
Finally, with all the syntactic improvement in PHP, creating a Closure object to go deal with the current limitations of the callable type feels like a non-issue.
Best regards,
Gina P. Banyard
[1] Zend: Make Closure covariant to callable by Girgias · Pull Request #15492 · php/php-src · GitHub
[2] in return type class with __invoke method is not a callable · Issue #18161 · php/php-src · GitHub
[3] PHP: rfc:deprecate_partially_supported_callables
[4] GitHub - Girgias/unify-typing-modes-rfc: PHP RFC: Unify PHP's typing modes · GitHub