PHP抽象静态类方法的替代模型

6

好的,我已经阅读了这里关于这个问题的帖子,但我认为这是一个具体而新的问题。

我想要的功能是我们错误地称之为“抽象静态方法”的功能。也就是说:我想要一个类,该类要求扩展它的类实现某些静态方法

似乎有两种方法可以解决不允许抽象静态的常见问题,但两种方法都不太优雅。

问题

以下会生成一个错误:“PHP Strict Standards:Static function A::fn() should not be abstract”。

<?php
abstract class A
{
     abstract static public function fn();
}

class B extends A
{
    static public function fn()
    {
         // does something on class vars etc.
    }
}

解决方案1:使用接口

<?php
interface iA {
    static function fn();
}


abstract class A implements iA 
{
} // obviously this would have other stuff in it in reality

class B extends A
{
    static public function fn()
    {
         // does something on class vars etc.
    }
}

这样做的问题在于接口假定(规定)所有方法都是公共的。因此,虽然这实现了要求抽象类的子类具有某些静态方法的目标,但它只能用于公共方法;仍然无法确保A的子类实现受保护的静态方法。
当方法完全在静态数据上工作但不应从“外部”调用时,受保护的静态方法非常有用。
解决方案2:异常
abstract class A
{
     static public function fn()
     {  
         throw new Exception(get_called_class() . " must implement fn()");
     }

}

class B extends A
{
    static public function fn()
    {
         // does something on class vars etc.
    }
}

这在运行时如果调用fn()是有效的。但是在运行时处理编码语法错误并不实用。而且,虽然这可能是一种方法的hack,但对于每种方法来说需要更多的代码。 这个设计有什么问题,以至于语言正确地禁止它吗?看起来很奇怪,有各种方式要求子类提供大多数类型的方法,但不包括静态方法。

最初的缺陷在于它们本来就不应该是静态的。当您使用对象时,所有描述的问题都将消失,并且易于实现。 - Gordon
是的,你可以通过去C来解决从A到B的问题,但这样你就不在B了。类变量非常有用,当数据在该类的所有对象之间共享时。 - artfulrobot
对我而言,它们更像是一个指示器,表示有一个等待被提取的对象。请查看Flyweight Pattern和TypeObject/Powertype,看看它们是否更适合。 - Gordon
使用这些模式并不能解决问题——轻量级模式因为共享数据不是不可变的;类型对象因为无法提供编译时验证。 - artfulrobot
2个回答

2
这是因为静态方法属于它们所定义的类。无论继承树结构如何,A::fn()B::fn()都是两种不同的方法。因此,将A::fn()定义为abstract几乎没有意义。
也许你在考虑的方法根本不应该是抽象的?如果想要使用任何类型的多态性,必须涉及对象。

我理解这些方法属于类,但是如果在C中未定义,则class C extends B {}; C::fn()将调用B::fn()。问题是如何强制B提供这些静态方法。 - artfulrobot
你已经解释了“如何”。我认为问题是“为什么不呢?” ;) - Fabian Schmengler

0

我可能完全错误,但我使用没有问题

abstract class A
{
     abstract static public function fn();
}

class B extends A
{
    static public function fn()
    {
         print 1;
    }
}

B::fn();

它会输出1。我已经在这里运行了你的代码。你使用的是哪个版本的php?


2
PHP 5.3。您在编译时未启用 E_STRICT(即不要在代码中设置它,因为那会太晚)。尝试编辑您的 php.ini 文件并添加 error_reporting = E_ALL | E_STRICT - artfulrobot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接