提问者:小点点

如何强制实现受保护的静态函数


我正在尝试编写一个抽象类(或接口)来强制扩展类实现受保护的静态函数。但这对于抽象类和接口来说都是不可能的。

错误:

  • 静态函数不应该是抽象的
  • 接口成员的存取类型必须省略

有什么想法可以做到吗?

更新

目的基本上是静态调用公共函数。这样就不需要实例化类。也不需要使_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();
}

共1个答案

匿名用户

从理论和实践的角度来看,没有真正需要声明静态方法抽象。

抽象方法是让子类填充空白。这通常是因为父类(原始抽象类)执行一些通用操作,但可以/必须适应某些特定情况,因此可以强制子类在其他通用算法中只实现这个特定的变量部分。抽象方法应该是更大算法中的空白点。

父方法将调用其抽象方法的实现,而不知道或关心谁实现它们或它们是如何实现的:

abstract class Foo {

    public function someAlgo() {
        $foo = $this->doSomethingSpecific();
        ...
    }

    abstract protected function doSomethingSpecific();

}

Foo不关心谁或什么填写空白doAsthing具体,它只依赖于它的存在和它的签名,抽象强制执行。实现此方法的特定对象或它如何实现它是可变的。这很重要,也是问题的核心。

在这种情况下,声明静态方法抽象是非常无用的。任何静态方法都可以作为非静态方法实现,所以在这里没有用。如果类本身应该像上面描述的那样作为更大的泛型算法的一部分调用抽象方法,那么就不需要静态方法。

因此,静态方法剩下的唯一场景是公共静态方法,它可以从任何地方调用:

abstract class Foo {

    abstract public static function bar();

}

class Baz extends Foo {

    public static function bar() { ... }

}

Baz::bar();

问题是,因为抽象类Foo本身并没有调用这个函数,而是这个函数只从外部代码调用,所以你不是在谈论填空方法,而是在谈论接口。所以,你应该使用接口来代替。
但即使在那里,因为你必须在源代码中键入特定的类名,硬编码,所以接口也没有什么意义。

声明接口或抽象方法签名的意义在于,您希望修复方法签名,以便任何代码都可以调用该特定方法,而无需关心它具体调用的对象。但是由于您必须对类名进行硬编码,因此调用它的对象没有可变性。如果您键入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可以依赖于它具有do一些特定方法。实现该方法的特定对象无关紧要,并且会有所不同。

abstract class Foo {

    abstract public static function bar();

}

class Baz extends Foo {

    public static function bar() { ... }

}

Baz::bar();

你在这里到底依赖或抽象了什么?你可以非常肯定Baz每次都会有bar()方法,因为你只在同一个硬编码类上调用它。这里没有什么是可变的。