428

设想:

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)以下内容:

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

class MyClass {
    use A {
        calc as traitcalc;
    }

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

没有任何效果。

有没有办法让它工作或者我必须完全覆盖比这更复杂的特征函数:)

4

5 回答 5

745

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

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

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

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

该特征不是一个类。您不能直接访问其成员。它基本上只是自动复制和粘贴...

于 2012-08-13T17:30:31.810 回答
17

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

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 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看到它的工作原理

于 2014-06-08T13:00:32.423 回答
13

如果有兴趣,另一种方法是使用额外的中间类来使用正常的 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);
    }
}
于 2015-06-08T05:04:18.393 回答
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
于 2020-08-09T23:52:44.620 回答
4

使用另一个特征:

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
于 2017-08-20T22:27:04.923 回答