避免特征冲突-use_once


avoiding trait collisions - use_once?

我有两个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();
    }
}

但我一直收到错误

致命错误:特性方法smallTalk尚未应用,因为在D 上与其他特性方法发生冲突

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

您需要阅读:冲突解决

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

为了解决同一类中使用的特征之间的命名冲突需要使用而不是运算符来选择冲突的方法。

由于这只允许排除方法,因此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;
    }
}

这里有一种避免编写大量代码的方法。基本上是使用匿名类并调用本质上来自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();
    }
}