最近我一直在努力学习PHP,我发现自己被trait缠住了。我理解横向代码重用的概念,并且不希望必然地继承抽象类。我不明白的是:使用特征和使用界面之间的关键区别是什么?

我曾试着搜索过一篇像样的博客文章或文章,解释什么时候使用其中一种或另一种,但到目前为止,我找到的例子似乎非常相似,甚至完全相同。


当前回答

如果你懂英语,知道trait的意思,它就是这个名字的意思。它是一个无类的方法和属性包,您可以通过输入use将其附加到现有类。

基本上,你可以将它与单个变量进行比较。闭包函数可以从作用域外部使用这些变量,这样它们就有了作用域内部的值。他们是强大的,可以在任何地方使用。如果trait被使用,也会发生同样的情况。

其他回答

接口是一种契约,它表明“这个对象能够做这件事”,而trait则赋予对象做这件事的能力。

trait本质上是在类之间“复制和粘贴”代码的一种方式。

试着阅读这篇文章,PHP的特点是什么?

描述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 SayWorld {
    public function sayHello() {
        echo 'World!';
    }
}

所以如果你想在其他类中使用sayHello函数,而不需要重新创建整个函数,你可以使用trait,

class MyClass{
  use SayWorld;

}

$o = new MyClass();
$o->sayHello();

酷吧!

不只是函数,你可以使用trait中的任何东西(function, variables, const…)你也可以使用多个trait: SayWorld, AnotherTraits;

接口

  interface SayWorld {
     public function sayHello();
  }

  class MyClass implements SayWorld { 
     public function sayHello() {
        echo 'World!';
     }
}

因此,这就是接口与特征的不同之处:您必须在实现的类中重新创建接口中的所有内容。接口没有实现,接口只能有函数和常量,不能有变量。

我希望这能有所帮助!

接口定义了实现类必须实现的一组方法。

当trait被使用时,方法的实现也会出现——这在接口中不会发生。

这是最大的不同。

PHP RFC的水平重用:

trait是一种在单继承语言(如PHP)中代码重用的机制。Trait旨在通过允许开发人员在不同类层次结构中的几个独立类中自由地重用方法集来减少单个继承的一些限制。

trait只是为了代码重用。

Interface只是提供了要在类中定义的函数的签名,它可以根据程序员的判断使用。这样就为我们提供了一组类的原型。

供参考, http://www.php.net/manual/en/language.oop5.traits.php