Interface Default Methods improves backwards compatibility when changing interfaces, but also add a way to have multi-inheritance in PHP.
I think this is very useful for PHP library developers.
They can add methods and provide a default implementation without breaking code (and if they only throw an exception).
For example Doctrine could add a addAll
method to the Collection interface and provide a basic implementation that uses the existing add
method under the hood.
Since interfaces (in other programming languages) don't add member fields, the this
won't need to be adjusted (by an offset) and the interface default methods just get added to the virtual method table (vtable) of the class, if they are not implemented by the class.
This is what an abstract class is for. Using Brents blog example, you'd create a default instance which was an abstract, this abstract would implement the default methods and the interface.
i really like the intention of this RFC, but as i see it the method resolution is backward. If you have two Interfaces that define the same method with incompatible signatures, the first-used Interface is blamed for being incompatible with the second:
interface I1 { public function foo(); } interface I2 { public function foo(string $bar): int; } // The latter interface method's signature wins the compatibility requirement: class C implements I1, I2 { } // Fatal error: Declaration of I1::foo() must be compatible with I2::foo(string $bar): int class C implements I2, I1 { } // Fatal error: Declaration of I2::foo(string $bar): int must be compatible with I1::foo()
The RFC would reverse this, keeping the method from the first-used. This also departs from replacement patterns found elsewhere, like associative arrays (the last definition of a key wins) and inheritance (an instance's members visible to the parent chain override the parents).
there are abstract classes where you can exactly do this
An interface defines... well.. just an interface. Not the implementation.
The feature of having default implementation is kind of already there: just use traits or abstract classes. Having any implementation in the interface makes the code blurry. When can I rely on an interface being totally a pure interface, when is it half-interface with some implementations?
It opens also a way for introducing new behavior and automatically populated to all implementations. Even to implementations where the default behavior would be plainly wrong. Wonder if my tests would show any sign of something being wrong. If I did my code based on an interface, like a contract, suddenly the contract could change without me noticing it.
Interfaces in PHP are not "pure interfaces" (as some have pointed out here) since they can contain constants, so interfaces in PHP are partially abstract classes. The concept of a “pure interface” includes only methods. In PHP, interfaces must contain default methods.
Interfaces should not contain any logic. Implementing multiple interfaces containing the same methods would also result in a new problem: which implementation should be used? Using traits, you have to choose manually using the use keyword. In this RFC no solution is provided.
Interfaces should not contain logic.
This RFC introduces a mess, because the implementation must be separated from the contract. As someone said: "if multi-inheritance is the subject, a specific RFC shall be done on this".
Interface should not provide any implementation details, it's only a contract even for default.
No code in Interfaces. It should be used for contracts
It would have been a perfect solution to replace all those abstract classes that are made just as a compatibility layer between versions. And if someone doesn't like this: old way would be still working.
A big NO for this one. Interfaces are interfaces, they declare the signature and introducing a contract for the implementing classes. If you need "default" implementation, you must do that in an abstract class. Let's not confuse different things into one.
Interfaces must be OO contracts without code. PHP already has the traits to implement shared methods. Mixing both wouldn't be of any help.
A new syntax for declaring the “set” operation visibility of an object property
The "pipe operator" |>
allows you to chain multiple function calls in a more convenient way.
Chain method on newly created objects without parentheses