如何覆盖特征函数,并从覆盖函数调用它?

场景:

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

这段代码不起作用,我无法找到一种方法来调用trait函数,就像它是继承的一样。我尝试调用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);
}
}

没有什么工作。

有没有办法让它起作用,或者我必须完全覆盖比这复杂得多的trait函数:)

136362 次浏览

你的最后一个也差不多了:

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


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


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

trait不是一个类。你不能直接访问它的成员。基本上就是自动复制和粘贴…

如果类直接实现方法,它将不会使用trait版本。也许你在想的是:

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

因为子类不直接实现方法,如果有父类的方法,它们将首先使用trait的方法。

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

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)

你也可以提供重写的方法,但仍然可以像下面这样访问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

你可以看到它在http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5处工作

如果感兴趣的话,还有一种替代方法——使用一个额外的中间类来使用正常的OOO方式。这简化了父: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);
}
}

使用另一个特征:

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

另一种变化:在trait中定义两个函数,一个是执行实际任务的受保护函数,一个是调用受保护函数的公共函数。

如果类想要重写函数,这只是避免了使用'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

这基本上是一个引用,但如果trait是代码的一部分,而不是一个包,您可以使用一个函数来检查是否存在另一个函数,并返回它而不是当前的函数。

trait A {
function calc($v) {
if(method_exists($this, 'calcClass'))
{
$this->calcClass($v)
}
return $v+1;
}
}


class MyClass {
use A;


function calcClass($v) {
return $v+2;;
}
}


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

我希望这能有所帮助。