我想知道在当前的 PHP 5.4 实现中是否有任何充分的理由可以解释为什么这种行为是可能的:
trait T {
public function test(PDO $pdo) {}
}
class C {
use T;
public function test(DOMDocument $dom) {}
}
我认为类使用特征这一事实保证了该类具有可用的特定接口。但在这里,如果我们无意中出于其他目的重写了特征方法,我们甚至不会收到严格标准通知,就像经典继承一样。
这是故意允许的吗?做什么用?
此行为已记录在案。来自 php.net (http://php.net/manual/en/language.oop5.traits.php):
从基类继承的成员被成员覆盖 由特征插入。优先顺序是来自以下成员 当前类重写 Trait 方法,返回重写 继承的方法。
此处没有任何通知理由。
编辑:
我查阅了一些更严肃的文献来阐明这个主题:)。看起来这种行为是特质定义的一部分。他们被要求以这种方式工作。这是来自研究“特征:可组合的行为单元”(欧洲面向对象编程会议记录):
特质组合的另一个性质是组合顺序为 不相关的,因此冲突的特征方法必须明确地 消除歧义(参见第 3.5 节)。中定义的方法之间的冲突 由合并的特征定义的类和方法使用 以下两条优先规则。
– 类方法优先于特征方法。
– Trait 方法优先于超类方法。这是从扁平化属性得出的,该属性指出特征方法的行为就好像它们是在类本身中定义的一样。
您可以在这里阅读更多内容:http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf
很晚的答案,但是:@BenMorel 似乎您期望 Traits 表现得像 Interfaces,但 Traits 和 Interfaces 不是同一件事,并且不是为相同目的而设计的。
接口是与外界的契约,确保每个实现类都可以相同地使用。任何方法签名偏离的任何类都会破坏接口,并且当 PHP 解释器遇到类定义时(甚至在类实例化之前)会被 PHP 解释器正确标记。
接口契约对于外界来说非常重要,以至于类的接口列表出现在实现类的左大括号之前:
class Foo implements FooInterface, BarInterface {
// method definitions here...
}
同时,Trait 可以方便地在类内部重用代码。重用的基于 Trait 的代码实际上可能是完全私有的,并且对类的用户来说是不可见的。
Traits 对外界的“不重要性”反映在以下事实:Trait 引用出现在引用类的大括号之间,这使得它们比 Interface 引用更不可见:
class Foo implements FooInterface, BarInterface {
use FooTrait, BarTrait;
// method definitions here...
}
接受的答案当然是完全正确的。我只是觉得接口和特征之间的进一步区分可能会有所帮助。