更新:我并不是唯一一个思考这个问题的人,它似乎确实是一个bug。请参见此处。修复的那一天将是美妙的一天!:)
它最初是I love PHP traits! I'm going to use them everywhere! ^_^
,现在已经变成了Thought Exercise / Learning Experience >_<
。
考虑以下示例:
trait TheErrorOfYourWays{
public function booboo(){
echo 'You had a booboo :(';
}
}
trait SpectacularStuff1 {
use TheErrorOfYourWays;
}
trait SpectacularStuff2 {
use TheErrorOfYourWays;
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2;
}
这导致(明显不那么明显):
致命错误:由于DoSomethingSpectacular上存在与其他特征方法的冲突,因此尚未应用特征方法booboo。
所以我的问题是:如何解决特征中的方法冲突?有可能实现重叠性状的"遗传"吗?如果是这样,什么是"正确"的方法
我为什么要这样做:
- 我想创建自我包含的特征和类(混搭风格)如果这是可能的,我想说"使用",然后神奇的东西一定会发生。不必挠头思考,"现在这个特性又在哪个命名空间中?"等等
- 当我做一些"冒险"的事情,发现自己无意中制造了冲突时,不必快速编辑类别和特征
- 当时看来是个好主意
我尝试过的:
- PHP手册
- 谷歌
- 所以包括这个问题->不是这个场景的正确答案
- 发现了这个,但我使用的是PHP版本5.5.1。它是固定的,对吧?对吧
一个由"as"、别名组成的奇妙阵列,甚至在不同的地方、时代、宇宙等。包括但不限于:
trait SpectacularStuff1 { use TheErrorOfYourWays{ TheErrorOfYourWays::booboo as booboo1; } } trait SpectacularStuff2 { use TheErrorOfYourWays{ TheErrorOfYourWays::booboo as booboo2; } } class DoSomethingSpectacular { use SpectacularStuff1, SpectacularStuff2 { /* Tried separately, but included here for brevity's sake */ SpectacularStuff1::booboo as booboo3; SpectacularStuff2::booboo as booboo4; } }
和
use TheErrorOfYourWays as Erroneous1; trait SpectacularStuff1 { use Erroneous1{ Erroneous1::booboo as booboo1; } } use TheErrorOfYourWays as Erroneous2; trait SpectacularStuff2 { use Erroneous2{ Erroneous2::booboo as booboo2; } }
我理解:
- 我可以将TheErrorOfYourWays更改为一个类,并使booboo()静态,但我想了解这种特定的特征行为
- 我可以从特性中删除TheErrorOfYourWays并在类中使用它,但这很难"自给自足"。每次我使用这些特性时,我都必须记住在类中使用TheErrorOfYourWays,即使我没有直接从类中调用booboo()。听起来很危险
- 我可能犯了一些新手语法错误,或者未能深入理解混叠。如果是,请。。。解释慢慢地
- 也许有更好的方法可以做到这一点。如果是,请。。。解释慢慢地
- 我可能过早地对PHP充满热情,而PHP还没有做到这一点。让我轻轻地下来
谢谢
您需要使用关键字insteadof
来解决Traits中的冲突。
Source
重写您的
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2 {
/* Tried separately, but included here for brevity's sake */
SpectacularStuff1::booboo as booboo3;
SpectacularStuff2::booboo as booboo4;
}
}
到
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2
{
SpectacularStuff1::booboo insteadof SpectacularStuff2;
SpectacularStuff2::booboo insteadof SpectacularStuff1;
}
}
将解决冲突。
所以非官方的"官方"答案是:
你可以在没有混叠的情况下完成它,而不是代替或做任何事情!但还没有。。。
我从5.5.1升级到5.5.6,但都是徒劳的。当修复程序可用时,我将更新此答案。值得注意的是,您可以直接调用trait静态函数。以下示例有效:
trait TheErrorOfYourWays{
public static function booboo($thisTrait){
echo 'You had a booboo :( in '.$thisTrait.'<br>';
}
}
trait SpectacularStuff1 {
public function boobooTest1(){
TheErrorOfYourWays::booboo(__TRAIT__);
}
}
trait SpectacularStuff2 {
public function boobooTest2(){
TheErrorOfYourWays::booboo(__TRAIT__);
}
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2;
}
$boobooAChoo = new DoSomethingSpectacular();
$boobooAChoo->boobooTest1(); // You had a booboo :( in SpectacularStuff1
$boobooAChoo->boobooTest2(); // You had a booboo :( in SpectacularStuff2
是的,是的,你也可以用一个类来做到这一点,但上一季的类是sooo。
我找到了另一种修复临时问题的方法:
trait A {
public function foo(){
echo 'foo';
}
}
trait B {
public function foofoo(){
return $this->foo () . 'foo';
}
}
trait C {
public function foobar(){
return $this->foo () . 'bar';
}
}
class DoSomethingSpectacular {
use A, B, C;
public function foobarfoofoo () {
echo $this->foobar () . $this->foofoo ();
}
}
它的工作原理是:)
一个小技巧,只需将函数booboo
添加到类DoSomethingSpectacular
<?php
trait TheErrorOfYourWays{
public function booboo(){
echo 'You had a booboo :(';
}
}
trait SpectacularStuff1 {
use TheErrorOfYourWays{
TheErrorOfYourWays::booboo as booboo1;
}
}
trait SpectacularStuff2 {
use TheErrorOfYourWays{
TheErrorOfYourWays::booboo as booboo2;
}
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2 {
/* Tried separately, but included here for brevity's sake */
SpectacularStuff1::booboo as booboo3;
SpectacularStuff2::booboo as booboo4;
}
//very ugly hack
public function booboo() {}
}
这是在PHP 7.3:3v4l.org/qulMv中修复的。这意味着,在两个或多个派生特征中使用一个或多个子特征,然后在类中使用派生特征是没有问题的!
请注意,不幸的是,PHP 7.3迁移指南中没有记录它,但它存在于变更日志中(相同的特征方法会在组合过程中引发错误)。
实现这一点的一种方法是使用抽象方法。我称之为";扁平化特征";,或者它也可以被称为";性状的依赖性注入";。这更像是一个广义的解决方案,而不是具体的解决方案。
您的示例可以更改为:
trait TheErrorOfYourWays
{
public function booboo(): string
{
return 'booboo';
}
}
trait SpectacularStuff1
{
abstract public function booboo(): string;
}
trait SpectacularStuff2
{
abstract public function booboo(): string;
}
class DoSomethingSpectacular
{
use TheErrorOfYourWays;
use SpectacularStuff1;
use SpectacularStuff2;
}
这就是我个人认为特质变得强大的地方:你可以写一个完全独立的特质,并在任何你想用的地方使用它。换句话说,它们可以完全独立。这就是为什么我喜欢特性(或者至少PHP特性)。
虽然我更喜欢这样使用特征,但可能会有使特征相互依赖的用例。例如,将一些相关的特征分组为一个大特征。