PHP中Trait和抽象类的区别

59

我最近接触到 PHP 中的 Traits,并试图理解它们。在我的研究中,我偶然发现了这个 Stack Overflow 问题:Traits vs. Interfaces。被接受的答案提到了以下内容:

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

当使用 trait 时,方法的实现也会随之而来——这在接口中不会发生。

到目前为止,这听起来和接口与抽象类之间的区别完全一样。所以这引发了一个后续问题:

  • Trait 和抽象类在 PHP 中有什么区别?

我知道我只能从一个抽象类扩展,而另一方面可以使用任意数量的 traits。但这真的是唯一的区别吗?我仍然不完全理解 traits 及其用法。


2
可能有用的链接:https://dev59.com/_GEi5IYBdhLWcg3w4Pjr#20866390 - Sebastian Brosch
2个回答

73

特征(Traits)允许您在类之间共享代码而不强制您进入特定的类层次结构。比如说,您想要所有的类都有一个方便的实用方法 foo($bar)。没有特征,您有两种选择:

  • 在每个类中独立地实现它,导致代码冗余;
  • 从一个公共的(抽象)祖先类继承。

这两种解决方案都不理想,各有不同的权衡。代码冗余显然是不可取的,而从一个公共祖先继承会使您的类层次结构设计变得不灵活。

特征通过让您在特征中实现foo($bar),并让每个类可以单独“导入”,来解决这个问题,同时仍然允许您根据业务逻辑要求设计您的类层次结构,而不是语言需求。


3
如果我理解得对的话,traits基本上是为了在几个没有关联的类之间使用相同的代码而设计的? - simon
7
没错,可以把它看作是一些小的组成部分,你可以用它们组合出一个类(组合)来。根据你的应用程序中代码可重用性的程度,你甚至可以将所有东西都实现为特征,并将一些特征以各种配置组合成实际的类。 - deceze
2
你觉得这像是帮助函数吗? - Jeremy Belolo
1
@Jeremy 那可能是最常见的用例,但本身过于狭窄。如上所述,如果在您的情况下有意义,您可以纯粹地通过traits来组成整个类。 - deceze
2
你也可以将它们与接口结合使用,例如在接口中定义一些方法,并使用 trait 提供实现,这样你的实现比抽象类更灵活(因为它不限于单个类型)。 - MADforFUNandHappy
没错,但是有时我发现需要使用抽象类作为“粘合剂”来连接接口、它们相对的实现特征和一些不太适合于trait的方法(如__construct,这取决于一个人遵循的编码风格)。最终仍然会受到初始抽象的限制。不过,可能有一种完全避免使用“abstract”的方法。 - Kamafeather

12

并不完全是这样... 让我们引用官方文档来解释:

Trait类似于类,但仅旨在以细粒度和一致的方式分组功能。无法独立实例化Trait。它是传统继承的补充,可以横向组合行为;也就是说,应用类成员而不需要继承。

因此,Trait用于组合目的,以使类执行某些逻辑/行为。如果您从另一个/抽象类继承,通常是出于多态性的目的,并且您会获得一个独立的继承/类层次结构,这可能是可取的,也可能不是。

我认为这完全取决于上下文、架构和您要做什么。


很棒的解释。 - Alexander Behling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接