如何覆盖特征函数并从被覆盖的函数中调用它?
Posted
技术标签:
【中文标题】如何覆盖特征函数并从被覆盖的函数中调用它?【英文标题】:How to override trait function and call it from the overridden function? 【发布时间】:2012-08-09 23:15:54 【问题描述】:场景:
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);
没有任何作用。
有没有办法让它工作,或者我必须完全覆盖比这更复杂的特征函数:)
【问题讨论】:
【参考方案1】:你的最后一个就快到了:
trait A
function calc($v)
return $v+1;
class MyClass
use A
calc as protected traitcalc;
function calc($v)
$v++;
return $this->traitcalc($v);
特征不是一个类。您不能直接访问其成员。它基本上只是自动复制和粘贴...
【讨论】:
只是为了澄清——一旦你的类定义了相同的方法,它会自动覆盖特征的。正如@ircmaxell 提到的,当它为空时,该特征会填充方法。 @PhillipWhelan 如果您可以添加有关“无法按预期工作”的更多信息,那就太好了。这样写对理解会出现什么样的错误行为没有多大帮助,也不能向我们保证这不是您的暂时错误。也许有一些关于你正在谈论的问题的问题? (最终)谢谢。 问题是特征中的所有其他方法都不再包括在内。 仅供参考:如果您的特征函数是静态的,您可以通过调用A::calc(1)
访问该函数
正如 Phillip 提到的(我认为),您将如何为一种特征的一种方法执行此操作,同时仍然像正常一样包含具有相同特征的所有其他方法?最好不要明确引用每种方法。【参考方案2】:
如果类直接实现方法,则不会使用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
因为子类不直接实现该方法,所以如果有其他使用父类的方法,它们将首先使用该特征的方法。
如果你愿意,特征可以使用父类中的方法(假设你知道方法会在那里)例如
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看到它的工作原理
【讨论】:
【参考方案3】:如果有兴趣,另一种方法 - 使用额外的中间类来使用正常的 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);
【讨论】:
这种方法将消除您使用trait
s 所拥有的任何优势。就像在多个类中组合多个特征(例如,一个类中的特征 A、B、另一个类中的特征 B、C、D,另一个类中的特征 A、C 等等)
不,使用这种方法,您仍然拥有拥有特质的优势。您可以在 IntClass 中使用此特性,但如果您愿意,也可以在许多其他类中使用它。如果仅在 IntClass 中使用 Trait,它将毫无用处。在这种情况下,最好将 calc() 方法直接放在该类中。
这完全不适合我。 ScreenablePerson::save()
存在,Candidate
使用 Validating
特征并扩展 ScreenablePerson
,并且所有三个类都有 save()
。
我同意这很有趣。它有效,因为对于扩展类,特征方法实际上存在于父类中。我个人认为,如果您发现自己处于这种情况会很方便,但我不建议您按设计这样做。【参考方案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
【讨论】:
【参考方案5】:另一种变体:在 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
【讨论】:
以上是关于如何覆盖特征函数并从被覆盖的函数中调用它?的主要内容,如果未能解决你的问题,请参考以下文章