Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why PHP Trait can't implement interfaces?

I'm wondering why PHP Trait (PHP 5.4) cannot implement interfaces.

Update from user1460043's answer => ...cannot require class which uses it to implement a specific interface

I understand that it could be obvious, because people could think that if a Class A is using a Trait T which is implementing an interface I, than the Class A should be implementing the interface I undirectly (and this is not true because Class A could rename trait methods).

In my case, my trait is calling methods from the interface that the class using the trait implements.

The trait is in fact an implementation of some methods of the interface. So, i want to "design" in the code that every class that want to use my trait have to implement the interface. That would allow the Trait to use class methods defined by the interface and be sure they are existing in the class.

like image 803
Leto Avatar asked Feb 02 '13 20:02

Leto


People also ask

Can a PHP trait implement interface?

Traits can not implement interfaces. A trait allow both classes to use it for common interface requirement.

Can PHP implement multiple interfaces?

Yes, more than two interfaces can be implemented by a single class. From the PHP manual: Classes may implement more than one interface if desired by separating each interface with a comma.

Is PHP trait good?

PHP Traits are Bad On the surface, there is strong support for PHP traits because using them can help reduce code duplication throughout your application. In addition, they can help improve maintainability and the cleanliness of your code.

How can we avoid implementing all methods interface?

However, you can avoid this by following the below approach: Declare the missing methods abstract in your class. This forces you to declare your class abstract and, as a result, forces you to subclass the class (and implement the missing methods) before you can create any objects.


2 Answers

The really short version is simpler because you can't. That's not how Traits work.

When you write use SomeTrait; in PHP you are (effectively) telling the compiler to copy and paste the code from the Trait into the class where it's being used.

Because the use SomeTrait; is inside the class, it can't add implements SomeInterface to the class, because that has to be outside the class.

"why aren't Traits types in PHP? "

Because they can't be instantiated. Traits are really just a language construct (telling the compiler to copy and paste the trait code into this class) as opposed to an object or type that can be referenced by your code.

So, i want to "design" in the code that every class that want to use my trait have to implement the interface.

That can be enforced using an abstract class to use the trait and then extending classes from it.

interface SomeInterface{     public function someInterfaceFunction(); }  trait SomeTrait {     function sayHello(){         echo "Hello my secret is ".static::$secret;     } }  abstract class AbstractClass implements SomeInterface{     use SomeTrait; }  class TestClass extends AbstractClass {     static public  $secret = 12345;      //function someInterfaceFunction(){         //Trying to instantiate this class without this function uncommented will throw an error         //Fatal error: Class TestClass contains 1 abstract method and must therefore be          //declared abstract or implement the remaining methods (SomeInterface::doSomething)     //} }  $test = new TestClass();  $test->sayHello(); 

However - if you do need to enforce that any class that uses a Trait has a particular method, I think you may be using traits where you should have been abstract classes in the first place.

Or that you have your logic the wrong way round. You're meant to require classes that implement interfaces have certain functions, not that if they have certain functions that they must declare themselves as implementing an interface.

Edit

Actually you can define abstract functions inside Traits to force a class to implement the method. e.g.

trait LoggerTrait {      public function debug($message, array $context = array()) {         $this->log('debug', $message, $context);     }      abstract public function log($level, $message, array $context = array()); } 

However this still doesn't allow you to implement the interface in the trait, and still smells like a bad design, as interfaces are much better than traits at defining a contract that a class needs to fulfill.

like image 91
Danack Avatar answered Oct 14 '22 06:10

Danack


There's a RFC: Traits with interfaces suggests following to be added to the language:

trait SearchItem implements SearchItemInterface {     ... } 

Methods required by the interface can either be implemented by the trait, or declared as abstract, in which case it is expected that class that uses the trait implements it.

This feature is currently not supported by the language, but it is under consideration (current status of the RFC is: Under Discussion).

like image 33
Ilija Avatar answered Oct 14 '22 05:10

Ilija