为什么 PHP Trait 不能实现接口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14665978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why PHP Trait can't implement interfaces?
提问by Leto
I'm wondering why PHP Trait (PHP 5.4) cannot implement interfaces.
我想知道为什么 PHP Trait (PHP 5.4) 不能实现接口。
Update from user1460043's answer => ...cannot require class which uses it to implement a specific interface
来自 user1460043 的回答的更新 => ...不能要求使用它来实现特定接口的类
I understand that it could be obvious, because people could think that if a Class Ais using a Trait Twhich is implementing an interface I, than the Class Ashould be implementing the interface Iundirectly (and this is not true because Class Acould rename trait methods).
我知道这可能是显而易见的,因为人们可能会认为如果 aClass A正在使用Trait T正在实现 an 的 a interface I,那么Class A应该interface I间接实现 the (这不是真的,因为Class A可以重命名 trait 方法)。
In my case, my trait is calling methods from the interface that the class using the trait implements.
就我而言,我的 trait 是从使用该 trait 的类实现的接口调用方法。
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.
trait 实际上是接口的一些方法的实现。所以,我想在代码中“设计”每个想要使用我的特征的类都必须实现接口。这将允许 Trait 使用由接口定义的类方法,并确保它们存在于类中。
回答by Danack
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.
当您用use SomeTrait;PHP编写时,您(有效地)告诉编译器将 Trait 中的代码复制并粘贴到正在使用它的类中。
Because the use SomeTrait;is inside the class, it can't add implements SomeInterfaceto the class, because that has to be outside the class.
因为use SomeTrait;是在班级内部,所以不能添加implements SomeInterface到班级,因为那必须在班级之外。
"why aren't Traits types in PHP? "
“为什么 PHP 中没有 Traits 类型?”
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.
因为它们不能被实例化。Traits 实际上只是一种语言构造(告诉编译器将 trait 代码复制并粘贴到此类中),而不是可以被您的代码引用的对象或类型。
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 usethe trait and then extending classes from it.
这可以通过use对特征使用抽象类然后从它扩展类来强制执行。
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.
但是 - 如果您确实需要强制使用 Trait 的任何类都有一个特定的方法,我认为您可能在最初应该是抽象类的地方使用了 Trait。
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.
实际上,您可以在 Traits 中定义抽象函数来强制类实现该方法。例如
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.
然而,这仍然不允许您在 trait 中实现接口,并且仍然闻起来像一个糟糕的设计,因为在定义一个类需要履行的契约时,接口比 trait 好得多。
回答by Ilija
There's a RFC: Traits with interfacessuggests following to be added to the language:
有一个RFC: Traits with interfaces建议将以下内容添加到语言中:
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.
接口所需的方法可以由 trait 实现,也可以声明为抽象的,在这种情况下,需要使用 trait 的类实现它。
This feature is currently not supported by the language, but it is under consideration (current status of the RFC is: Under Discussion).
该语言目前不支持此功能,但正在考虑中(RFC 的当前状态是:讨论中)。
回答by user1460043
[...] 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.
[...] 在代码中“设计”每个想要使用我的 trait 的类都必须实现接口。这将允许 Trait 使用由接口定义的类方法,并确保它们存在于类中。
This sounds very reasonable and I would not say that there has to be anything wrong with your design. Traits have been suggested with this idea in mind, see the second point here:
这听起来很合理,我不会说你的设计一定有什么问题。已经根据这个想法建议了特征,请参阅此处的第二点:
- A trait providesa set of methods that implement behaviour.
- A trait requiresa set of methods that serve as parameters for the provided behaviour.
- [...]
- trait提供了一组实现行为的方法。
- 特征需要一组方法作为所提供行为的参数。
- [...]
Sch?rli 等人,特征:行为的可组合单元,ECOOP'2003,LNCS 2743,第 248–274 页,Springer Verlag,2003,第 2 页
So it would be maybe more appropriate to say that you want a trait to requirean interface, not to "implement" it.
所以说你想要一个特性需要一个接口,而不是“实现”它可能更合适。
I do not see a reason why it should be impossible to have this "trait requires (its consumer classes to implement) an interface" feature in PHP, but currently it seems to be missing.
我不明白为什么在 PHP 中不可能有这个“特性需要(它的消费者类来实现)一个接口”特性,但目前它似乎缺失了。
As @Danack notes in his answer, you can use abstract functions in the trait to "require" them from classes that use the trait. Unfortunately you can not do this with private functions.
正如@Danack 在他的回答中指出的那样,您可以在特征中使用抽象函数从使用特征的类中“要求”它们。不幸的是,你不能用私有函数来做到这一点。
回答by NekoOs
I agree with the response of @Danack, however I will complement it a little.
我同意@Danack 的回应,但我会补充一点。
The really short version is simpler because you can't. That's not how Traits work.
真正简短的版本更简单,因为你不能。这不是特征的工作方式。
I can only think of few cases in which what you request is necessary and is more evident as a design problem than as a language failure. Just imagine that there is an interface like this:
我只能想到少数情况,在这种情况下,您的请求是必要的,并且作为设计问题比作为语言失败更明显。试想一下,有一个这样的界面:
interface Weaponize
{
public function hasAmmunition();
public function pullTrigger();
public function fire();
public function recharge();
}
A traithas been created that implements one of the functions defined in the interfacebut in the process uses other functions also defined by the interface, prone to the error that if the class that uses the feature does not implement the interfaceeverything fails to pull the trigger
已经创建了一个trait,它实现了接口中定义的一个函数,但在这个过程中使用了接口中定义的其他函数,容易出现错误,如果使用该特性的类没有实现接口,一切都无法拉取扳机
trait Triggerable
{
public function pullTrigger()
{
if ($this->hasAmmunition()) {
$this->fire();
}
}
}
class Warrior
{
use Triggerable;
}
An easy solution is simply to force the class that uses the traitto implement those functions as well:
一个简单的解决方案是强制使用trait的类也实现这些功能:
trait Triggerable
{
public abstract function hasAmmunition();
public abstract function fire();
public function pullTrigger()
{
if ($this->hasAmmunition()) {
$this->fire();
}
}
}
So the traitisn't completely dependent on the interface, but a proposal to implement one of its functions, since when using the traitthe class will demand the implementation of the abstract methods.
因此trait并不完全依赖于interface,而是实现其功能之一的建议,因为在使用trait 时,类将要求实现抽象方法。
Final design
最终设计
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.
}
}
Please excuse my English
请原谅我的英语

