PHP 5.4:为什么类可以使用不同的签名重写特征方法?

问题描述 投票:0回答:2

我想知道在当前的 PHP 5.4 实现中是否有任何充分的理由可以解释为什么这种行为是可能的:

trait T {
    public function test(PDO $pdo) {}
}

class C {
    use T;
    public function test(DOMDocument $dom) {}
}

我认为类使用特征这一事实保证了该类具有可用的特定接口。但在这里,如果我们无意中出于其他目的重写了特征方法,我们甚至不会收到严格标准通知,就像经典继承一样。

这是故意允许的吗?做什么用?

php inheritance overriding traits
2个回答
29
投票

此行为已记录在案。来自 php.net (http://php.net/manual/en/language.oop5.traits.php):

从基类继承的成员被成员覆盖 由特征插入。优先顺序是来自以下成员 当前类重写 Trait 方法,返回重写 继承的方法。

此处没有任何通知理由。

编辑:

我查阅了一些更严肃的文献来阐明这个主题:)。看起来这种行为是特质定义的一部分。他们被要求以这种方式工作。这是来自研究“特征:可组合的行为单元”(欧洲面向对象编程会议记录):

特质组合的另一个性质是组合顺序为 不相关的,因此冲突的特征方法必须明确地 消除歧义(参见第 3.5 节)。中定义的方法之间的冲突 由合并的特征定义的类和方法使用 以下两条优先规则。

– 类方法优先于特征方法。

– Trait 方法优先于超类方法。这是从扁平化属性得出的,该属性指出特征方法的行为就好像它们是在类本身中定义的一样。

您可以在这里阅读更多内容:http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf


0
投票

很晚的答案,但是:@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... }

接受的答案当然是完全正确的。我只是觉得接口和特征之间的进一步区分可能会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.