Why PHP Trait can't implement interfaces?
我想知道为什么php特性(php 5.4)不能实现接口。
从user1460043的答案更新=>…不能要求使用它来实现特定接口的类
我理解这是显而易见的,因为人们可以认为,如果一个
在我的例子中,我的特性是从使用特性的类实现的接口调用方法。
这个特性实际上是接口的一些方法的实现。所以,我想在代码中"设计"每个想要使用我的特性的类都必须实现接口。这将允许特性使用由接口定义的类方法,并确保它们存在于类中。
真正简短的版本更简单,因为你不能。这不是特征的工作方式。
当你用PHP编写
因为
"why aren't Traits types in PHP?"
因为它们不能被实例化。特性实际上只是一种语言构造(告诉编译器将特性代码复制并粘贴到这个类中),而不是代码可以引用的对象或类型。
So, i want to"design" in the code that every class that want to use
my trait have to implement the interface.
它可以使用抽象类来强制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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(); |
但是-如果您确实需要强制任何使用特性的类具有特定的方法,那么我认为您可能正在使用特性,因为您首先应该是抽象类。
或者你的逻辑错误。您的目的是要求实现接口的类具有某些函数,而不是如果它们具有某些函数,那么它们必须声明自己是实现接口的。
编辑
实际上,您可以在特性内部定义抽象函数来强制类实现该方法。例如
1 2 3 4 5 6 7 8 |
然而,这仍然不允许您在特性中实现接口,而且仍然有一种糟糕的设计味道,因为在定义类需要实现的契约时,接口比特性要好得多。
有一个RFC:带有接口的特性建议在语言中添加以下内容:
1 2 3 4 | trait SearchItem implements SearchItemInterface { ... } |
接口所需的方法可以由特性实现,也可以声明为抽象的,在这种情况下,使用特性的类应该实现它。
该语言目前不支持该功能,但正在考虑该功能(RFC的当前状态为:讨论中)。
[...] 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.
这听起来很合理,我不会说你的设计有什么问题。考虑到这一想法,我们提出了一些特点,请看下面的第二点:
- A trait provides a set of methods that implement behaviour.
- A trait requires a set of methods that serve as parameters for the provided behaviour.
- [...]
SCH?RLI等人,《特征:可组合的行为单位》,Ecoop'2003,LNCS 2743,第248-274页,Springer Verlag,2003,第2页。
所以说您希望一个特性需要一个接口,而不是"实现"它可能更合适。
我不明白为什么在PHP中不可能有这样的"特性需要(它的消费者类实现)一个接口"特性,但是目前它似乎已经丢失了。
正如@danack在他的答案中指出的,您可以使用特性中的抽象函数从使用特性的类中"要求"它们。不幸的是,您不能用私有函数来实现这一点。
我同意@danack的回复,不过我会补充一点。
The really short version is simpler because you can't. That's not how Traits work.
我只能在少数情况下认为您请求的内容是必要的,并且比语言故障更明显是一个设计问题,想象一下有这样一个接口:
1 2 3 4 5 6 7 | interface Weaponize { public function hasAmmunition(); public function pullTrigger(); public function fire(); public function recharge(); } |
已经创建了一个实现接口中定义的一个函数的特性,但在进程中使用了接口也定义的其他函数,这很容易出错,如果使用该特性的类不实现接口,则所有操作都无法拉动触发器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | trait Triggerable { public function pullTrigger() { if ($this->hasAmmunition()) { $this->fire(); } } } class Warrior { use Triggerable; } |
一个简单的解决方案就是简单地强制使用特性的类实现这些函数:
1 2 3 4 5 6 7 8 9 10 11 12 | trait Triggerable { public abstract function hasAmmunition(); public abstract function fire(); public function pullTrigger() { if ($this->hasAmmunition()) { $this->fire(); } } } |
所以这个特性并不完全依赖于接口,而是一个实现它的一个函数的建议,因为当使用这个特性时,类将要求实现抽象方法。
最终设计1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | interface Weaponize { public function hasAmmunition(); public function pullTrigger(); public function fire(); public function recharge(); } trait Triggerable { public abstract function hasAmmunition(); public abstract function fire(); public function pullTrigger() { if ($this->hasAmmunition()) { $this->fire(); } } } class Warrior implements Weaponize { use Triggerable; public function hasAmmunition() { // TODO: Implement hasAmmunition() method. } public function fire() { // TODO: Implement fire() method. } public function recharge() { // TODO: Implement recharge() method. } } |
对不起,英语