【问题标题】:avoiding trait collisions - use_once?避免特征冲突 - use_once?
【发布时间】:2016-03-28 19:27:47
【问题描述】:

我有两个 PHP 特征,每个特征都继承自相同的第三个特征:

trait C {
    public function smallTalk() {
        echo 'c';
    }
}

trait A {
    use C;
    public function ac() {
        echo 'a'.smallTalk();
    }
}

trait B {
    use C;
    public function bc() {
        echo 'b'.smallTalk();
    }
}

我想在课堂上同时使用它们:

class D {
    use A, B;
    public function acbc() {
        echo ac().bc();
    }
}

但我不断收到错误

致命错误:Trait 方法 smallTalk 尚未应用,因为与 D 上的其他 trait 方法有冲突

我知道use_once 不是一个东西,但我正在寻找与require_once 或include_once 提供的相同功能,但用于特征。这个例子被简化了。我真正的 C 有很多方法,并且被超过 2 个特征继承,所以我真的不想每次使用超过 1 个这些特征时都必须重复一长串 insteadof。

【问题讨论】:

  • 短版:不,手动处理冲突是使用特征的代价。
  • 我怀疑你在滥用特质。我只使用特质作为最后的手段。这个答案对替代方案有很好的解释(在 C++ 中,但它们主要适用于任何 OOP 语言)stackoverflow.com/questions/406081/…

标签: php inheritance multiple-inheritance


【解决方案1】:

您需要阅读:Conflict Resolution

如果两个 Traits 插入同名的方法,则发生致命错误 产生,如果冲突没有明确解决。

为了解决同一类中使用的 Traits 之间的命名冲突, insteadof 运算符需要用于准确选择其中一个 冲突的方法。

由于这只允许排除方法,as 运算符可以是 用于允许包含以下冲突方法之一 另一个名字。

例子:

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}

【讨论】:

  • 你读过这个问题吗? “我真正的 C 有很多方法,并且被超过 2 个特征继承,所以我真的不想每次使用超过 1 个这些特征时都必须重复一长串的而不是。”我知道我可以做到你所说的,但我想问是否有更好的解决方案。
  • 您将无法通过其他方式解决冲突。使用特征+扩展。如果您想“正确”地做所有事情-不要尝试在特质的帮助下做所有事情。您可以创建一个 C 类。从 C 扩展的 D。没有一个真实的例子 - 很难说哪种架构是正确的。我建议熟悉 SOLID。它可以帮助选择架构。
  • 赞成,因为这是正确的答案,即使 OP 不喜欢它是正确的答案。
  • 这不是真的正确答案,因为它忽略了原始问题的精神和意图。答案是,在 php 中我们还没有一个很好的解决方案来处理这个问题。唯一的解决方案是每个方法的别名或重命名。 php的trait使用还有不足之处;特别是它会尝试在多个地方加载相同的特征(在 Trait2 中使用 Trait1;然后尝试在您的类中使用这两个;它应该解决 Trait1 已经被包含,但它会发生致命的冲突)。跨度>
【解决方案2】:

这是避免编写大量代码的一种方法。基本上就是利用匿名类,调用本质上来自trait C的公共函数。

这可能仍然取决于您的代码的实际结构(例如,您是否使用$this):

trait C
{
    public function smallTalk()
    {
        return 'c';
    }
}

trait A
{
    public function ac()
    {
        // anonymous class to avoid leaking all Trait C functions to
        // the classes that didn't sign up for that. Can't see other bad
        // side effects except for being inefficient
        $local_class = new class {
            use C;
        };
        return 'a' . (new $local_class())->smallTalk();
    }
}

trait B
{
    public function bc()
    {
        $local_class = new class {
            use C;
        };
        return 'b' . (new $local_class())->smallTalk();
    }
}

所以你现在可以同时包含这两个特征:

class D
{
    use A, B;
    public function acbc()
    {
        echo $this->ac() . $this->bc();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    • 2018-02-03
    相关资源
    最近更新 更多