Re: RFC proposal: Invokable interface
| From: | Gina P. Banyard | Date: | Tue, 31 Mar 2026 12:53:07 +0000 |
| Subject: | Re: RFC proposal: Invokable interface | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-130516@lists.php.net to get a copy of this message | ||
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:
> https://github.com/php/php-src/pull/21574
>
> 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 https://3v4l.org/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] https://github.com/php/php-src/pull/15492
[2] https://github.com/php/php-src/issues/18161
[3] https://wiki.php.net/rfc/deprecate_partially_supported_callables
[4] https://github.com/Girgias/unify-typing-modes-rfc