最近我一直在努力学习PHP,我发现自己被trait缠住了。我理解横向代码重用的概念,并且不希望必然地继承抽象类。我不明白的是:使用特征和使用界面之间的关键区别是什么?
我曾试着搜索过一篇像样的博客文章或文章,解释什么时候使用其中一种或另一种,但到目前为止,我找到的例子似乎非常相似,甚至完全相同。
最近我一直在努力学习PHP,我发现自己被trait缠住了。我理解横向代码重用的概念,并且不希望必然地继承抽象类。我不明白的是:使用特征和使用界面之间的关键区别是什么?
我曾试着搜索过一篇像样的博客文章或文章,解释什么时候使用其中一种或另一种,但到目前为止,我找到的例子似乎非常相似,甚至完全相同。
当前回答
接口定义了实现类必须实现的一组方法。
当trait被使用时,方法的实现也会出现——这在接口中不会发生。
这是最大的不同。
PHP RFC的水平重用:
trait是一种在单继承语言(如PHP)中代码重用的机制。Trait旨在通过允许开发人员在不同类层次结构中的几个独立类中自由地重用方法集来减少单个继承的一些限制。
其他回答
接口定义了实现类必须实现的一组方法。
当trait被使用时,方法的实现也会出现——这在接口中不会发生。
这是最大的不同。
PHP RFC的水平重用:
trait是一种在单继承语言(如PHP)中代码重用的机制。Trait旨在通过允许开发人员在不同类层次结构中的几个独立类中自由地重用方法集来减少单个继承的一些限制。
描述trait的一个常用比喻是:trait是带有实现的接口。
在大多数情况下,这是一种很好的思考方式,但两者之间存在一些微妙的差异。
首先,instanceof操作符不能与trait一起工作(即,trait不是一个真正的对象),因此不能使用它来查看一个类是否具有某个trait(或者查看两个本来不相关的类是否共享一个trait)。这就是他们所说的横向代码重用的结构。
现在PHP中有一些函数可以让您获得类使用的所有特征的列表,但是特征继承意味着您需要进行递归检查,以可靠地检查类在某个时刻是否具有特定的特征(PHP doco页面上有示例代码)。不过,它当然不像instanceof那样简单干净,以我之见,这个特性会让PHP变得更好。
而且,抽象类仍然是类,因此它们不能解决与多重继承相关的代码重用问题。请记住,您只能扩展一个类(真实的或抽象的),但可以实现多个接口。
我发现trait和接口非常适合一起使用来创建伪多重继承。例如:
class SlidingDoor extends Door implements IKeyed
{
use KeyedTrait;
[...] // Generally not a lot else goes here since it's all in the trait
}
这样做意味着您可以使用instanceof来确定特定的Door对象是否是Keyed的,您知道您将得到一组一致的方法,等等,并且所有的代码在所有使用KeyedTrait的类中都位于一个位置。
接口是一种契约,它表明“这个对象能够做这件事”,而trait则赋予对象做这件事的能力。
trait本质上是在类之间“复制和粘贴”代码的一种方式。
试着阅读这篇文章,PHP的特点是什么?
主要的区别在于,对于接口,您必须在实现上述接口的每个类中定义每个方法的实际实现,因此您可以让许多类实现相同的接口但具有不同的行为,而trait只是注入到类中的代码块;另一个重要的区别是trait方法只能是类方法或静态方法,不像接口方法也可以(通常是)是实例方法。
trait只是为了代码重用。
Interface只是提供了要在类中定义的函数的签名,它可以根据程序员的判断使用。这样就为我们提供了一组类的原型。
供参考, http://www.php.net/manual/en/language.oop5.traits.php