从理论和实践的角度来看,没有真正需要声明静态方法抽象。
抽象方法可以让子类填空。这通常是因为父类(原始抽象类)执行一些通用操作,但可以/必须适应某些特定情况,因此可以强制子类在其他通用算法中仅实现这个特定的变量部分。抽象方法应该是在更大的算法中的空白点。
父方法会调用其抽象方法的实现而不知道或关心谁实现它们或如何实现它们:
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
Foo 不在乎是谁或什么填充了空白doSomethingSpecific,它只依赖于它的存在及其签名,abstract 强制执行。实现此方法或它如何实现它的具体对象是变量。这很重要,也是问题的核心。
在这种情况下,声明一个静态方法抽象是毫无用处的。任何静态方法都可以作为非静态方法来实现,所以这里没有用。如果类本身应该调用抽象方法作为如上所述的更大泛型算法的一部分,则不需要静态方法。
因此,静态方法剩下的唯一场景是public static 方法,它可以从任何地方调用:
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
问题是,由于 abstract class Foo 本身并没有调用这个函数,而是这个函数只是从外部代码调用,所以你并不是真的在谈论 fill-in-the-blank方法,你说的是一个接口。因此,您应该改用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() 方法,因为你只是在同一个硬编码类上调用它。这里没有什么是可变的。