关于php:如何覆盖trait函数并从重写函数调用它?

How to override trait function and call it from the overridden function?

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

这段代码不起作用,我也找不到一种方法可以像继承一样调用特征函数。我试着打电话给self::calc($v)static::calc($v)parent::calc($v)A::calc($v)和如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as traitcalc;
    }

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

没有效果。

有没有办法让它工作,或者我必须完全重写比这个复杂得多的特征函数:)


你上一个就快到了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
trait A {
    function calc($v) {
        return $v+1;
    }
}

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

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

这个特点不是一个阶级。您不能直接访问它的成员。基本上只是自动复制和粘贴…


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

因为子类不直接实现该方法,所以如果不使用父类的特性,它们将首先使用特性的特性。

如果您愿意,特性可以在父类中使用方法(假设您知道该方法会存在),例如。

1
2
3
4
5
6
7
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)

您还可以提供重写方法,但仍然可以按如下方式访问特征方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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"
"
;
print (new MySecondTraitChildClass())->calc(2); // will print 6.5

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


如果感兴趣的话,另一种方法是使用普通OOO方法的额外中间类。这简化了对parent::methodname的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);
    }
}


使用另一个特性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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