Hey all! Long time browser, first time emailer. I wanted to start a pre-RFC
discussion on the proposal of opt-in implicit interfaces / structural
typing / "golang style interfaces".
I have an early mostly working POC at
https://github.com/php/php-src/compare/master...SpencerMalone:php-src:implicit,
and was curious if this was an idea that could get any traction as an RFC?
For those who don't want to open the link, it's essentially:
implicit interface Drawable {
public function draw(): void;
}
class Circle {
public function draw(): void {
}
}
assert((new Circle()) instanceof Drawable); // This would be true
There is some previous art around here in the form of...
https://wiki.php.net/rfc/protocol_type_hinting - I couldn't find any
discussion on this other than reading that the author withdrew all their
RFCs for unrelated reasons I think? Some of the core ideas here I think are
still relevant, although in my implementation I chose to use syntax that
adds a keyword onto the interface rather than at the call sites because I
wanted to provide the ability for interface definers to keep their
interfaces as explicit if they wanted, as well as... Well honestly, adding
angle brackets around objects feels like a syntax misstep since that
pattern is very associated with generics in my mind. I could be convinced
of this though if that's the syntax people prefer.
https://externals.io/message/115554#115603 - Convinced me that others may
want this as well, although again that proposed syntax ended up stepping on
the toes of attributes. I do think this does a good job of explaining why
I want this.
- Spencer
Hi Spencer,
Hey all! Long time browser, first time emailer. I wanted to start a pre-RFC discussion on the proposal of opt-in implicit interfaces / structural typing / "golang style interfaces".
I have an early mostly working POC at https://github.com/php/php-src/compare/master...SpencerMalone:php-src:implicit, and was curious if this was an idea that could get any traction as an RFC?
For those who don't want to open the link, it's essentially:
implicit interface Drawable { public function draw(): void; } class Circle { public function draw(): void { } } assert((new Circle()) instanceof Drawable); // This would be trueThere is some previous art around here in the form of...
https://wiki.php.net/rfc/protocol_type_hinting - I couldn't find any discussion on this other than reading that the author withdrew all their RFCs for unrelated reasons I think? Some of the core ideas here I think are still relevant, although in my implementation I chose to use syntax that adds a keyword onto the interface rather than at the call sites because I wanted to provide the ability for interface definers to keep their interfaces as explicit if they wanted, as well as... Well honestly, adding angle brackets around objects feels like a syntax misstep since that pattern is very associated with generics in my mind. I could be convinced of this though if that's the syntax people prefer.
https://externals.io/message/115554#115603 - Convinced me that others may want this as well, although again that proposed syntax ended up stepping on the toes of attributes. I do think this does a good job of explaining why I want this.
- Spencer
I think this is an interesting idea, but personally, I would prefer to see classes always explicitly declare their interfaces. An interface is a contract, and implementing the interface is agreeing to conform to the contract. Just because a class has the shape of an interface doesn't mean it follows the contract. implicit would probably be most useful for very simple interfaces, but those are exactly the kind of interfaces that could be misinterpreted. For example, this poorly designed class:
class DeckOfCards {
public ?Card $mostRecentlyDrawnCard;
public function draw() : void { ... }
}
should not be instanceof the Drawable interface, because it doesn't conform to the contract, even though it structurally matches.
Perhaps slightly less torturously,
class Canvas {
public array $contents; //list<Drawable>
private CanvasInternalRepresentation $internalRepresentation
public function draw() : void { ... update the canvas's internal representation ... }
public function data($imageType) : string { .. } // return binary blob of $imageType data from the internal representation
}
This Canvas takes a list of Drawables and uses a draw() method to update its internal representation. But it itself is not Drawable (let's say, because Canvas can't be nested for whatever reason).
In real code, there's probably a lot of things that structurally would conform to some sort of simple Cache/Cacheable or Request/Response interface but for reasons wouldn't obey whatever implied contract those interfaces would demand.
In my opinion, a better solution would be to allow for extensions that allow declaring interface conformances. e.g.
extension Circle implements Drawable {
// We have now explicitly declared that Circle is a Drawable and conforms to its contract.
// This extension body is empty because Circle already has a conforming draw method,
// but if it didn't, we could add one here and it would be treated as part of the Circle class.
}
Of course, this would be a much more involved proposal than implicit interfaces, which does have elegance in its simplicity.
-John
The extension idea is interesting! I hadn't thought of that. Autoloading
might be a PITA with that, I'm trying to think of how you would manage that?
On the subject of "mistaken typing" or implicit interfaces being met by
classes that don't actually do the desired behavior, I think you're right
it's a risk, my counterargument is typescript and golang both have implicit
interfaces in some form (well typescript calls them structural typing), but
I don't think in either language I've ever really run into a case where
that risk becomes a reality. I'm hesitant to declare this because I'm not
sure this is the best way to frame this from a PR perspective, but in many
respects this proposal is viewable as a syntax shortcut to duck typing,
which is already pretty common across PHP. While there are definitely
drawbacks to duck typing, it's still a very useful tool IMO (and becomes
very cumbersome if you need to duck type a larger set of functions).
Hi Spencer,
On Nov 7, 2025, at 12:05, Spencer Malone malone.spencer@gmail.com
wrote:Hey all! Long time browser, first time emailer. I wanted to start a
pre-RFC discussion on the proposal of opt-in implicit interfaces /
structural typing / "golang style interfaces".I have an early mostly working POC at
https://github.com/php/php-src/compare/master...SpencerMalone:php-src:implicit,
and was curious if this was an idea that could get any traction as an RFC?For those who don't want to open the link, it's essentially:
implicit interface Drawable { public function draw(): void; } class Circle { public function draw(): void { } } assert((new Circle()) instanceof Drawable); // This would be trueThere is some previous art around here in the form of...
https://wiki.php.net/rfc/protocol_type_hinting - I couldn't find any
discussion on this other than reading that the author withdrew all their
RFCs for unrelated reasons I think? Some of the core ideas here I think are
still relevant, although in my implementation I chose to use syntax that
adds a keyword onto the interface rather than at the call sites because I
wanted to provide the ability for interface definers to keep their
interfaces as explicit if they wanted, as well as... Well honestly, adding
angle brackets around objects feels like a syntax misstep since that
pattern is very associated with generics in my mind. I could be convinced
of this though if that's the syntax people prefer.https://externals.io/message/115554#115603 - Convinced me that others
may want this as well, although again that proposed syntax ended up
stepping on the toes of attributes. I do think this does a good job of
explaining why I want this.
- Spencer
I think this is an interesting idea, but personally, I would prefer to see
classes always explicitly declare their interfaces. An interface is a
contract, and implementing the interface is agreeing to conform to the
contract. Just because a class has the shape of an interface doesn't mean
it follows the contract. implicit would probably be most useful for very
simple interfaces, but those are exactly the kind of interfaces that could
be misinterpreted. For example, this poorly designed class:class DeckOfCards { public ?Card $mostRecentlyDrawnCard; public function draw() : void { ... } }should not be instanceof the Drawable interface, because it doesn't
conform to the contract, even though it structurally matches.Perhaps slightly less torturously,
class Canvas { public array $contents; //list<Drawable> private CanvasInternalRepresentation $internalRepresentation public function draw() : void { ... update the canvas's internal representation ... } public function data($imageType) : string { .. } // return binary blob of $imageType data from the internal representation }This Canvas takes a list of Drawables and uses a draw() method to update
its internal representation. But it itself is not Drawable (let's say,
because Canvas can't be nested for whatever reason).In real code, there's probably a lot of things that structurally would
conform to some sort of simple Cache/Cacheable or Request/Response
interface but for reasons wouldn't obey whatever implied contract those
interfaces would demand.In my opinion, a better solution would be to allow for extensions that
allow declaring interface conformances. e.g.extension Circle implements Drawable { // We have now explicitly declared that Circle is a Drawable and conforms to its contract. // This extension body is empty because Circle already has a conforming draw method, // but if it didn't, we could add one here and it would be treated as part of the Circle class. }Of course, this would be a much more involved proposal than implicit
interfaces, which does have elegance in its simplicity.-John
The extension idea is interesting! I hadn't thought of that.
Autoloading might be a PITA with that, I'm trying to think of how you
would manage that?On the subject of "mistaken typing" or implicit interfaces being met by
classes that don't actually do the desired behavior, I think you're
right it's a risk, my counterargument is typescript and golang both
have implicit interfaces in some form (well typescript calls them
structural typing), but I don't think in either language I've ever
really run into a case where that risk becomes a reality. I'm hesitant
to declare this because I'm not sure this is the best way to frame this
from a PR perspective, but in many respects this proposal is viewable
as a syntax shortcut to duck typing, which is already pretty common
across PHP. While there are definitely drawbacks to duck typing, it's
still a very useful tool IMO (and becomes very cumbersome if you need
to duck type a larger set of functions).
(Please do not top post.)
Languages with implicit interfaces like Go also go (no pun intended) "all in" on it. All methods on an object are defined externally, possibly not even in the same file. The whole standard lib was built on that model from the ground up. That's not the case in PHP.
I've been pondering extension functions for some time, and have kicked the idea around with John before. (I would do it as functions, a la Kotlin, not as a secondary class, like Rust.) Autoloading and efficiently determining that you need to call an extension are the key stumbling blocks (though my stance on autoloading at this point is "we've got opcache enabled 100% of the time, we have things like FrankenPHP, just front-load the file and move on with your life).
I could see implicit interfaces working in conjunction with extension functions, if we can figure those out. I'm not sure if they offer much value without them, given the state of PHP. It would basically mean you have to opt-out of a type rather than opt-in, as now. That could get... weird.
--Larry Garfield
Languages with implicit interfaces like Go also go (no pun intended) "all in" on it. All methods on an object are defined externally, possibly not even in the same file. The whole standard lib was built on that model from the ground up. That's not the case in PHP.
I've been pondering extension functions for some time, and have kicked the idea around with John before. (I would do it as functions, a la Kotlin, not as a secondary class, like Rust.) Autoloading and efficiently determining that you need to call an extension are the key stumbling blocks (though my stance on autoloading at this point is "we've got opcache enabled 100% of the time, we have things like FrankenPHP, just front-load the file and move on with your life).
I could see implicit interfaces working in conjunction with extension functions, if we can figure those out. I'm not sure if they offer much value without them, given the state of PHP. It would basically mean you have to opt-out of a type rather than opt-in, as now. That could get... weird.
--Larry Garfield
Opting out would both be weird, and from a practical standpoint, is unreasonable to ask of userspace developers.
For correctness, every potential implicit interface match would have to be explicitly declared as non-comforming in order to be correct. It's both very noisy and does not scale. From a library perspective, it's impossible: a library class can't possibly declare all the possible does_not_implement conformances because the entire universe of interfaces that might overlap its shape can't be known.
A pathological example might look something like:
class DeckOfCards
implements Shuffleable, \Deck\Drawable
// We don't actually import any of these, but we have to explicitly deny them because otherwise it will cause problems in end-user code
does_not_implement \FooGraphics\Drawable, \BarGraphics\Drawable, \ZodGraphics\Drawable, \GameEngine\TieInterface, \BarGameEngine\DeckDrawable, \Vehicle\Drawable
{...}
There's also a problem point with any code that calls get_declared_classes() and filters by instanceof SomeInterface. Now all that code is potentially broken (if implicit conformances don't meet contractual requirements). Would we need to add an implicit/explicit/either option to is_a() to make userspace able to correctly reason about types? Are there other cases where implicit conformance needs to be treated differently than explicit conformance?
Importing a package that has an implicit type would basically have to come with a warning, "don't make your classes look like this interface or else things might break".
And I'm sure someone would also find a creative way to abuse the trivial case, implicit interface AnyObject {}.
-John
I could see implicit interfaces working in conjunction with extension functions, if we can figure those out. I'm not sure if they offer much value without them, given the state of PHP. It would basically mean you have to opt-out of a type rather than opt-in, as now. That could get... weird.
--Larry Garfield
Opting out would both be weird, and from a practical standpoint, is
unreasonable to ask of userspace developers.For correctness, every potential implicit interface match would have to
be explicitly declared as non-comforming in order to be correct. It's
both very noisy and does not scale. From a library perspective, it's
impossible: a library class can't possibly declare all the possible
does_not_implement conformances because the entire universe of
interfaces that might overlap its shape can't be known.
OK, maybe opt-out wasn't the right term, since I agree marking "I do NOT implement interface X" is kinda ridiculous. :-) Implicit interfaces wouldn't really be opt-out, but they're more than the opt-in that we currently have.
--Larry Garfield
Hey all! Long time browser, first time emailer. I wanted to start a
pre-RFC discussion on the proposal of opt-in implicit interfaces /
structural typing / "golang style interfaces".
Hi and welcome :)
In general, I prefer explicit code over implicit, so wouldn't be an
enthusiastic supporter of this (although I might abstain rather than
voting against).
However, I though it worth mentioning that PHP has one implicit
interface already: any class with an __toString() method magically
implements Stringable. I've never really understood why, or why that
interface even exists; but at least having a general concept of
"implicit interface" would make it less magical.
--
Rowan Tommins
[IMSoP]
Hey all! Long time browser, first time emailer. I wanted to start a
pre-RFC discussion on the proposal of opt-in implicit interfaces /
structural typing / "golang style interfaces".Hi and welcome :)
In general, I prefer explicit code over implicit, so wouldn't be an
enthusiastic supporter of this (although I might abstain rather than
voting against).However, I though it worth mentioning that PHP has one implicit
interface already: any class with an __toString() method magically
implements Stringable. I've never really understood why, or why that
interface even exists; but at least having a general concept of
"implicit interface" would make it less magical.
__toString() is old. It may go all the way back to 5.0, but it was there at least as of 5.2. The problem is that there was no way to type against it. You could type string, but not string or object that implements string. When we got union types in 8.0, that was tempting but not yet possible. So Stringable was added basically for typing against string|Stringable. And it was made implicitly added because there were a bajillion __toString() functions in the wild already that shouldn't have to be modified before you could type against them.
</history lesson>
--Larry Garfield
__toString() is old. It may go all the way back to 5.0, but it was there at least as of 5.2. The problem is that there was no way to type against it.
I know all that. I've just never understood why you would want to type against it. The only thing you can do with that knowledge is turn the object into a string, so why not just ask for a string in the first place?
But I apologise for drifting off topic; the relevant point is that it works exactly how the proposed implicit interfaces would, so whatever reasoning was used for it might serve a useful example for other potential uses. If nothing else, being able to say "it's a built-in implicit interface" would be less confusing than explaining it as a magical special case.
Who knows, maybe there are people wishing they could type against other magic methods, who could do so by declaring their own implicit interfaces.
As I say, I'm personally much more interested in highly explicit code, so am more likely to go completely the opposite direction: use an empty interface, where the only thing you're doing is "tagging" a class as intended for a particular purpose.
But, I know there are people who like "duck typing", and implicit interfaces or structural typing give a way to formalise that, so I can see value for those people.
Rowan Tommins
[IMSoP]
Hey all! Long time browser, first time emailer. I wanted to start
a pre-RFC discussion on the proposal of opt-in implicit interfaces
/ structural typing / "golang style interfaces".Hi and welcome :)
In general, I prefer explicit code over implicit, so wouldn't be an
enthusiastic supporter of this [...]
However, I though it worth mentioning that PHP has one implicit
interface already: any class with an __toString() method magically
implements Stringable. I've never really understood why, or why that
interface even exists; but at least having a general concept of
"implicit interface" would make it less magical.
Good thinking, inspiring, in my eyes that __toString() magically,
both in the method as in the inverse of the direction towards the
Stringable interface definition, is rather stemming from the needs of
some object oriented PHP framework authors IIRC.
In terms of it as a historical artifact to learn from or take something
away from it for similar implicit interfaces, I'd like to add that I
find it rather explicit (like a parental advisory sticker on a CD jewel
case) due to the inability of PHP to resolve such (internal) interfaces
at place of use (the implements keyword) while there was no
problem with the implicit magic method.
This is perhaps why I as well have very little understanding what that
single instance has brought to the table finally, it appears to stand in
the way much too often for me on the observable surface.
The only hope I nevertheless had with it is, that it would have helped
to solve the problem of __toString() fatalling in the engine.
So Stringable/object{__toString(): string} is certainly a very special
example in its very own not as a magical special case, but it is a
fundamental special case every programming language that has "output"
has to solve. Not having any output would solve the turing problem
by its higher math, but such machines also have effectively undefined
themselves and by that any programming language. That problem is
inherit with output and it is the formatting of output, even if it
is only dumping the content of the process registers. What we can't
see does not exist.
So every programming language at that point must re-invent itself
somehow, as it certainly does not compile recursively, but rather
has the concepts of compiletime, runtime, whatnottime and the
recursion, direct or indirect, often a property stemming from these,
it (recursion) is always a thing, too.
- Recursion is the root of computation since it trades description
for time.
Unless strict normative rules are given by the design to prevent that
(e.g. to make things maintainable safely in the longtime), but every
extension will add, not remove, so longtime or eternity often only
remains the idea, bugs and regressions the reality along the road of
success.
If we take output then for a given, we have to solve this problem at
its core, otherwise we can't built upon it.
This is where yours mentioned implicit Stringable interface comes
into play. For those Framework authors it certainly was enough to
given them a way to go from a method pointer ("__toString") or a
memory pointer (the string), from a memory object to a PHP language
classlike object, e.g. by declaring the type with a function or
method parameter (in) or return value (out).
Regardless if only compiled once to its executable form,
ErrorException (PHP 5.1), or as in PHP userland compiled,
interpreted and re-compiled until it gets there:
What do you do when that error is to be handled and the error handler
is in userland (or at compile time) and includes (or has) more code to
be evaluated while handling the error still on the engine level?
See in PHP thanks to the scripts, we have this inane recursion
problem.
This is a bit like heart surgery on the open heart, the pump is still
pumping and one wrong cut everything can bleed out. The doctor may
survive, so in terms of software, there is not much need to really know
what we are doing here and can defer some work until later. In real life
this causes grave injuries if not deaths.
How successful such an implicit Stringable interface (PHP 8.0 IIRC) was
in this sense I do not know. I do not even know if the introduction of
Stringable has been discussed afterwards in that regard.
But I'm derailing, what I wanted to prolong on is, that Stringable in
itself as an "implicit" interface as you have rightfully mentioned, is
certainly touching many more parts than the suggested "implicit interface"
by Spence Malone would need to care about.
So what are other examples?
Tagging (with empty interfaces) often comes to my mind then, but all
interfaces, empty or not, also have the probem of the loading order
in PHP.
At place of use, where they would shine, requires not only to explicitly
define them (good!), but also to explicitly have them loaded. So there
perhaps is still a problem in PHP core to get compilation and execution
into a quite better order in the sense of their arrangement to make use
of the language with the runtime. The framework authors didn't had that
problem, because they voided it by separating each classlike into its
own file (object) and then let having PHP/SPL resolve the loading order
(a.k.a. class autoloading). At the core we can still see that problem
as separating each classlike into an object (file) of its own requires
preproduction (those are actually deployables, so we're not programming
any longer but have longtime stopped and already are building the
artifacts.) If there is something to strengthen, then it is the ability
of PHP developers to program in PHP, not to waste time thinking about
that they need to learn some special technique how to arrange their code
later on so that it fullfills some dependency, theirs dependency
managers and then call that the art of doing module management. This is
all longtime afterards and therefore always inherits any previous flaw at
the languages core every PHP framework author intends to not address at
all.
So in my opinion your raise of the dynamics from explicit to implicit
and vice-versa can bring interesting aspects to the table regardless
which style each of us is currently thinking to prefer, but as you
rightfully raised, PHP core developers should also confront themselves
on how to pick up the loose ends we still have while new authors make
useful suggestions to extend language-level intermediates. From PHP
history, IMHO (and regardless how I use or not use them), Traits are
a key milestone in this way of PHP design done right for me.
The proposal aligns well for me in that regard.
Stringable on the other hand, a bad example of everything but making
problems in core and use of the PHP language itself more visible; and
that is often a good thing, see the output problem above I mentioned,
my current understanding is that we always inherit that on computer
systems and when programming machines. So as long as we can get output,
we can benefit. Naturally we benefit from explicit output much more
then from implicit one - until otherwise.
- Every program is a part of some other program and rarely fits.
my 2 cents,
- h.k.
On Fri, Nov 7, 2025 at 5:05 PM Spencer Malone malone.spencer@gmail.com
wrote:
Hey all! Long time browser, first time emailer. I wanted to start a
pre-RFC discussion on the proposal of opt-in implicit interfaces /
structural typing / "golang style interfaces".I have an early mostly working POC at
https://github.com/php/php-src/compare/master...SpencerMalone:php-src:implicit,
and was curious if this was an idea that could get any traction as an RFC?For those who don't want to open the link, it's essentially:
implicit interface Drawable { public function draw(): void; } class Circle { public function draw(): void { } } assert((new Circle()) instanceof Drawable); // This would be trueThere is some previous art around here in the form of...
https://wiki.php.net/rfc/protocol_type_hinting - I couldn't find any
discussion on this other than reading that the author withdrew all their
RFCs for unrelated reasons I think? Some of the core ideas here I think are
still relevant, although in my implementation I chose to use syntax that
adds a keyword onto the interface rather than at the call sites because I
wanted to provide the ability for interface definers to keep their
interfaces as explicit if they wanted, as well as... Well honestly, adding
angle brackets around objects feels like a syntax misstep since that
pattern is very associated with generics in my mind. I could be convinced
of this though if that's the syntax people prefer.https://externals.io/message/115554#115603 - Convinced me that others may
want this as well, although again that proposed syntax ended up stepping on
the toes of attributes. I do think this does a good job of explaining why
I want this.
- Spencer
Hi Spencer,
A few years ago I had a go at it. In case it is useful in any way, you can
check it in
https://github.com/php/php-src/compare/master...pmmaga:php-src:implicit-interfaces
Regards,
Pedro
Hey all! Long time browser, first time emailer. I wanted to start a
pre-RFC
discussion on the proposal of opt-in implicit interfaces / structural
typing / "golang style interfaces".I have an early mostly working POC at
https://github.com/php/php-src/compare/master...SpencerMalone:php-src:implicit,
and was curious if this was an idea that could get any traction as an
RFC?For those who don't want to open the link, it's essentially:
implicit interface Drawable { public function draw(): void; }
If you may be that kind and allow an implicit interface to use a trait...
class Circle {
public function draw(): void {
}
}
... then the class could use a trait as well which is then closing the
distance to traits that are not able to full-fill interfaces and their
using classes, so the classes can borrow from the traits and both then
somewhat profit from implicit interfaces.
The "innerface" naturally could only use the non-body parts (abstract
parts) of the trait methods / properties, so the copy direction towards
the interface is a reduction to the interface the trait implies.
The trait then can be used in the implicit interface definition to do
both at once (defining an interface and providing an implementation).
assert((new Circle()) instanceof Drawable); // This would be true
and if I may add, truly great - regardless with or without such
trait reuse.
if it then could work en-par with function defintions (define after
use which currently "explicit" interfaces are not capable of) this
would make it a perfect and modern addition to the language in my
very own eyes.
There is some previous art around here in the form of...
[...]
- Spencer
- h.k.