与其他特质方法的冲突

51

我该如何处理具有相同名称的特征和方法?

trait FooTrait {
  public function fooMethod() {
        return 'foo method';
  }

  public function getRow() {
        return 'foo row';
  }
}

trait TooTrait {
    public function tooMethod() {
        return 'too method';
    }

    public function getRow() {
        return 'too row';
    }
}

class Boo
{
    use FooTrait;
    use TooTrait;

    public function booMethod() {
        return $this->fooMethod();
    }
}

错误,

致命错误:由于在Boo中存在与其他trait方法冲突,因此未应用getRow trait方法...

我该怎么办?

另外,当有两个相同的方法名时,如何从trait FooTrait中获取这个方法呢?

$a = new Boo;
var_dump($a->getRow()); // Fatal error: Call to undefined method Boo::getRow() in... 

编辑:

class Boo
{
    use FooTrait, TooTrait {
        FooTrait::getRow insteadof TooTrait;
    }

    public function booMethod() {
        return $this->fooMethod();
    }
}

如果我想通过 Boo 也从 TooTrait 获取方法 getRow,这可能吗?

3个回答

102

PHP文档中关于冲突的说明:

 

如果两个Trait插入了相同名称的方法,则会产生致命错误,除非显式解决冲突。

 

要解决在同一类中使用的Trait之间的命名冲突,需要使用insteadof运算符来选择冲突方法中的一个。

 

由于这仅允许排除方法之一,因此可以使用as运算符将一个具有冲突的方法包含到另一个名称下。

 

示例#5:冲突解决

 

在此示例中,Talker使用A和B Traits。由于A和B具有冲突的方法,它定义了从Trait B的smallTalk变体中使用,以及Trait A的bigTalk变体。

 

Aliased_Talker使用as操作符来能够在其他别名talk下使用B的bigTalk实现。

<?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;
    }
}

所以在你的情况下,可能是这样的

class Boo {
    use FooTrait, TooTrait {
        FooTrait::getRow insteadof TooTrait;
    }

    public function booMethod() {
        return $this->fooMethod();
    }
}

即使您单独使用 use 也可以正常工作,但我认为这样更清晰

或者使用 as 声明别名。


谢谢你的回答!我可以问一下 - 如果我也想通过 Boo 获取 TooTrait 中的 getRow 方法,这是否可能? - Run
3
声明一个别名:TooTrait::getRow as getRowOfToo;。试试看。 - Marco Acierno
也可以像这样破解它。在我看来,当前的行为不是预期的行为。我也期望,“as”会传递给使用类。 - lsblsb
请注意,令人惊讶的是,当类中的方法与在该类中使用的 trait 中具有相同名称的方法冲突时,您不会收到致命错误,即使 trait 的方法无法访问。 - Dan Chadwick

4

是的,这是可能的。您可以使用类似以下内容的方法(针对已编辑的内容):

class Boo {
    use FooTrait, TooTrait {
        FooTrait::getRow as getFooRow;
        TooTrait::getRow as getTooRow;
    }

    public function getRow(... $arguments)
    {
         return [ 'foo' => $this->getFooRow(... $arguments), 'too' => $this->getTooRow(... $arguments) ];
    }

    public function booMethod(... $arguments)
    {
        return $this->getFooRow(... $arguments);
    }
}

这是经过测试的代码吗? - Mohd Belal

0

有了被接受的答案,你可以涵盖所有可能的需求,但如果你的情况像我的一样简单,你可以创建一个 trait ,它使用另一个 trait ,这会导致冲突。

trait FooTrait {
  // ...

  public function fooMethod() {
        return 'foo method';
  }

  // ...
}

trait MyFooTrait {
    use FooTrait;

    public function fooMethod() {
        return 'my foo method';
    }
}

class Boo
{
    use MyFooTrait;
}

在我的情况下,FooTrait 来自供应商的 PHP 包,并且我想在自己应用程序的多个类中使用增强方法。

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