这是一个漫长而悲伤的故事。
当 PHP 5.2 首次引入此警告时,该语言还没有后期静态绑定。如果您不熟悉后期静态绑定,请注意这样的代码不会按您预期的方式工作:
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
撇开严格模式警告不谈,上面的代码不起作用。self::bar()
调用 infoo()
显式引用 的方法bar()
,ParentClass
即使foo()
作为 的方法调用也是如此ChildClass
。如果您尝试在关闭严格模式的情况下运行此代码,您将看到“ PHP 致命错误:无法调用抽象方法 ParentClass::bar() ”。
鉴于此,PHP 5.2 中的抽象静态方法毫无用处。使用抽象方法的全部意义在于,您可以编写调用该方法的代码,而无需知道它将调用什么实现——然后在不同的子类上提供不同的实现。但是由于 PHP 5.2 没有提供干净的方法来编写调用子类的静态方法的父类的方法,因此这种抽象静态方法的使用是不可能的。因此,在 PHP 5.2 中的任何使用都是糟糕的代码,可能是由于对关键字工作原理abstract static
的误解。self
对此发出警告是完全合理的。
但随后 PHP 5.3 出现了通过关键字引用方法被调用的类的能力static
(与关键字不同,self
关键字总是引用定义方法的类)。如果您更改self::bar()
为static::bar()
上面的示例,它在 PHP 5.3 及更高版本中可以正常工作。你可以在New self vs. new static阅读更多关于self
vs的内容。static
添加 static 关键字后,abstract static
抛出警告的明确论点就消失了。后期静态绑定的主要目的是允许父类中定义的方法调用子类中定义的静态方法;考虑到后期静态绑定的存在,允许抽象静态方法似乎是合理且一致的。
我猜你仍然可以提出保留警告的理由。例如,您可能会争辩说,由于 PHP 允许您调用抽象类的静态方法,因此在我上面的示例中(即使在通过替换为 修复它之后self
)static
您暴露了一个损坏ParentClass::foo()
的公共方法并且您真的不想暴露。使用非静态类——也就是说,使所有方法成为实例方法,并使所有方法的子对象成为单例或其他东西——将解决这个问题,因为是抽象的,不能被实例化,所以它的实例方法不能叫做。我认为这个论点很弱(因为我认为暴露ParentClass
ParentClass
ParentClass::foo()
没什么大不了的,使用单例而不是静态类通常是不必要的冗长和丑陋的),但您可能有理由不同意 - 这是一个有点主观的调用。
所以基于这个论点,PHP 开发人员在语言中保留了警告,对吗?
呃,不完全是。
上面链接的 PHP 错误报告 53081 要求删除警告,因为添加static::foo()
构造使抽象静态方法变得合理和有用。Rasmus Lerdorf(PHP 的创建者)首先将请求标记为虚假,然后通过一长串错误的推理来试图证明警告的合理性。然后,最后,发生了这种交换:
乔治奥
我知道但是:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
拉斯穆斯
对,这正是它应该如何工作的。
乔治奥
但这是不允许的:(
拉斯穆斯
什么是不允许的?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
这工作正常。你显然不能调用 self::B(),但是 static::B() 很好。
Rasmus 声称他的示例中的代码“工作正常”是错误的;如您所知,它会引发严格模式警告。我猜他是在没有开启严格模式的情况下进行测试。无论如何,困惑的拉斯穆斯将请求错误地关闭为“虚假”。
这就是为什么警告仍然在语言中的原因。这可能不是一个完全令人满意的解释——你可能来到这里希望警告有合理的理由。不幸的是,在现实世界中,有时选择来自平凡的错误和糟糕的推理,而不是来自理性的决策。这只是其中之一。
Luckily, the estimable Nikita Popov has removed the warning from the language in PHP 7 as part of PHP RFC: Reclassify E_STRICT notices. Ultimately, sanity has prevailed, and once PHP 7 is released we can all happily use abstract static
without receiving this silly warning.