如何覆盖trait函数并从重写函数调用它?

Shu*_*Shu 344 php traits

场景:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A;

    function calc($v) {
        $v++;
        return A::calc($v);
    }
}

print (new MyClass())->calc(2); // should print 4
Run Code Online (Sandbox Code Playgroud)

这段代码不起作用,我找不到像继承那样调用特征函数的方法.我试着打电话self::calc($v),static::calc($v)parent::calc($v),A::calc($v)以及以下内容:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as traitcalc;
    }

    function calc($v) {
        $v++;
        return traitcalc($v);
    }
}
Run Code Online (Sandbox Code Playgroud)

什么都行不通.

有没有办法使它工作或必须完全覆盖比这复杂得多的特征函数:)

irc*_*ell 600

你的最后一个几乎就在那里:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as protected traitcalc;
    }

    function calc($v) {
        $v++;
        return $this->traitcalc($v);
    }
}
Run Code Online (Sandbox Code Playgroud)

特质不是一个阶级.您无法直接访问其成员.它基本上只是自动复制和粘贴......

  • 只是为了澄清 - 一旦你的类定义了相同的方法,它会自动覆盖特征.当@ircmaxell为空时,该特征会填充该方法. (17认同)
  • 问题是特征中的所有其他方法都不再包含在内。 (4认同)
  • 正如Phillip提到的(我认为),您将如何对一种特征方法进行此操作,同时仍然包括与正常特征相同的所有其他方法?最好不要明确引用每种方法。 (4认同)
  • @PhillipWhelan会很好,如果你可以添加更多关于"不按预期工作"的信息.这样写的对于理解期望什么样的错误行为没有多大帮助,并且不能向我们保证这不是你的暂时错误.对于你所谈论的问题,可能有一些问题吗?(最终)谢谢. (2认同)
  • 我现在明白 PhillipWhelan 所说的如果他使用逗号就好了,就像这样:“当你这样做时,特征引入的其他方法可能不起作用,正如预期的那样。” 换句话说,他是说其他 trait 方法根本不起作用。Malhal 在他们的评论中为我们澄清了这一点。 (2认同)
  • @malhal 在什么情况下会发生这种情况?我[无法复制](https://3v4l.org/EWFnU)。 (2认同)
  • 仅供参考:如果您的特征函数是静态的,您可以通过调用`A :: calc(1)`来访问该函数 (2认同)

Yeh*_*sef 11

如果类直接实现该方法,则不会使用traits版本.也许你在想的是:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}

class MyChildClass extends MyClass{
}

class MyTraitChildClass extends MyClass{
    use A;
}

print (new MyChildClass())->calc(2); // will print 4

print (new MyTraitChildClass())->calc(2); // will print 3
Run Code Online (Sandbox Code Playgroud)

因为子类没有直接实现该方法,所以如果否则使用父类的那些,它们将首先使用该特征.

如果你愿意,trait可以在父类中使用方法(假设你知道方法会在那里),例如

trait A {
    function calc($v) {
        return parent::calc($v*3);
    }
}
// .... other code from above
print (new MyTraitChildClass())->calc(2); // will print 8 (2*3 + 2)
Run Code Online (Sandbox Code Playgroud)

您还可以提供覆盖的方法,但仍然可以按如下方式访问trait方法:

trait A {
    function trait_calc($v) {
        return $v*3;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}


class MyTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }
}


class MySecondTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }

    public function calc($v) {
      return $this->trait_calc($v)+.5;
    }
}


print (new MyTraitChildClass())->calc(2); // will print 6
echo "\n";
print (new MySecondTraitChildClass())->calc(2); // will print 6.5
Run Code Online (Sandbox Code Playgroud)

您可以在http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5上看到它的工作原理


Kar*_*k V 7

如果感兴趣的另一种方法 - 使用额外的中间类来使用普通的OOO方式.这简化了parent :: methodname的用法

trait A {
    function calc($v) {
        return $v+1;
    }
}

// an intermediate class that just uses the trait
class IntClass {
    use A;
}

// an extended class from IntClass
class MyClass extends IntClass {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这种方法可以通过使用`trait`s来削减你的任何优势.比如在多个类中组合多个特征(例如,类中的特征A,B,特征B,C,D在另一个类中,特征A,C在另一个类中等等) (6认同)
  • 不,使用这种方法,您仍然具有特征的优势.您可以在IntClass中使用此特征,但如果您愿意,也可以在许多其他类中使用它.如果Trait仅在IntClass中使用,那么Trait将毫无用处.在这种情况下,最好将calc()方法直接放在该类中. (3认同)

tar*_*hov 5

使用另一个特征:

trait ATrait {
    function calc($v) {
        return $v+1;
    }
}

class A {
    use ATrait;
}

trait BTrait {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}

class B extends A {
    use BTrait;
}

print (new B())->calc(2); // should print 4
Run Code Online (Sandbox Code Playgroud)


Gan*_*net 5

另一种变体:在特征中定义两个函数,一个执行实际任务的受保护函数,以及一个依次调用受保护函数的公共函数。

如果类想要覆盖该函数,这只会使类不必混乱“use”语句,因为它们仍然可以在内部调用受保护的函数。

trait A {
    protected function traitcalc($v) {
        return $v+1;
    }

    function calc($v) {
        return $this->traitcalc($v);
    }
}

class MyClass {
    use A;

    function calc($v) {
        $v++;
        return $this->traitcalc($v);
    }
}

class MyOtherClass {
    use A;
}


print (new MyClass())->calc(2); // will print 4

print (new MyOtherClass())->calc(2); // will print 3
Run Code Online (Sandbox Code Playgroud)