我试图编写一个抽象类(或接口)来强制扩展类实现受保护的静态函数。 但这对于抽象类和接口来说既不可能。
错误:
任何想法如何实现?
更新
目的基本上是静态调用公共函数。这样,该类不需要实例化。 也没有必要从类外部代码中调用_doSpecificStuff()。
abstract class Foo
{
public static function doStuff()
{
[generic code]
static::_doSpecificStuff();
}
// sth like that would be nice to have:
abstract static protected function _doSpecificStuff();
}
答案 0 :(得分:5)
从理论和实践的角度来看,没有必要申报静态方法摘要。
抽象方法可以让子类填充空白。这通常是因为父类(原始抽象类)执行一些通用操作,但可以/必须适应某些特定情况,因此可以强制子类在其他通用算法中仅实现此特定变量部分。抽象方法应该是较大算法中的空白点。
父方法会调用其抽象方法的实现而不知道或关心谁实现它们或 它们如何实现:
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
Foo
并不关心填充空白doSomethingSpecific
的人或者什么,它只依赖于abstract
强制实施的那里及其签名。实现此方法或其实现方式的特定对象是 variable 。这很重要,也是问题的核心。
在这种情况下,声明静态方法摘要是没用的。任何静态方法都可以作为非静态方法实现,因此这里没有用处。如果类本身应该将抽象方法称为如上所述的更大的通用算法的一部分,那么就不需要静态方法。
因此静态方法的唯一方案是public static
方法,可以从任何地方调用:
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
问题是,由于abstract class Foo
本身并不调用此函数,但此函数仅从外部代码调用,因此您并未真正谈论填空方法,您正在谈论界面。因此,您应该使用interface
代替
但即便如此,由于您必须在源代码中键入特定的类名,硬编码,因此接口也没有什么意义。
声明接口或抽象方法签名的关键在于您要修复方法签名,以便任何代码都可以调用该特定方法,而无需关心它特别调用它的对象。但由于您必须对类名进行硬编码,因此您调用它的对象没有可变性。如果您输入Baz::bar()
,您就会知道您正在调用哪种方法。因此,抽象界面/签名没有什么意义。
比较
interface FooInterface {
public function bar();
}
function baz(FooInterface $foo) {
$foo->bar();
}
由于接口声明,函数baz
可以依赖于具有bar()
方法的参数。实施该方法的具体对象是无关紧要的,并且会有所不同。
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
班级Foo
可以依赖doSomethingSpecific
方法。实施该方法的具体对象是无关紧要的,并且会有所不同。
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
你究竟在这里依赖或抽象出什么?您可以非常确定Baz
每次都会使用方法bar()
,因为您只能在相同的硬编码类上调用它。这里什么都不变。