Thi*_*eek 9 php interpreter abstract-class abstract-function
请考虑以下代码:
abstract class ExampleClass
{
public static function regularStaticFunction()
{
return static::abstractStaticFunction();
}
abstract protected static function abstractStaticFunction();
}
ExampleClass::regularStaticFunction();
Run Code Online (Sandbox Code Playgroud)
PhpStorm IDE对声明的声明发出警告abstractStaticFunction:
PHP严格标准:静态函数'abstractStaticFunction'不应该是抽象的.
静态函数不应该是抽象的.
但是,PHP在解析此类时会继续执行程序并输出以下内容:
PHP严格标准:静态函数ExampleClass :: abstractStaticFunction()在第7行的php shell代码中不应该是抽象的
在我看来,因为PHP允许对抽象类进行静态函数调用,所以不应该在抽象类上定义抽象静态函数.
为什么解释器在PHP中允许抽象静态函数,当它们是荒谬的时候?
Ger*_*ich 23
Mark Amery在这个答案中给出了很好的解释:
PHP错误报告53081,要求删除警告,因为添加
static::foo()构造使得抽象静态方法合理且有用.Rasmus Lerdorf(PHP的创建者)开始时将请求标记为虚假,并经历了一系列糟糕的推理,试图证明警告的合理性.然后,最后,这次交换发生:乔治
我知道但是:
Run Code Online (Sandbox Code Playgroud)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();拉斯穆斯
是的,这正是它应该如何运作的.
乔治
但是不允许:(
拉斯穆斯
有什么不允许的?
Run Code Online (Sandbox Code Playgroud)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声称他的例子中的代码"工作正常"是错误的; 如你所知,它会抛出严格模式警告.我猜他没有打开严格模式就开始测试了.无论如何,一个混乱的Rasmus将请求错误地关闭为"虚假".
这就是警告仍在语言中的原因.这可能不是一个完全令人满意的解释 - 你可能来到这里希望警告有合理的理由.不幸的是,在现实世界中,有时选择是出于世俗的错误和错误的推理而不是理性的决策.这只是其中一次.
幸运的是,可评估的Nikita Popov已经删除了PHP 7中语言的警告,作为PHP RFC的一部分:重新分类E_STRICT通知.最终,理智得到了普及,一旦PHP 7发布,我们都可以愉快地使用
abstract static而不会收到这个愚蠢的警告.
抽象静态函数并非无稽之谈!事实上,在我看来,它们实现了一些设计,比我在没有它们的语言(如 Java 或 C#)中使用的设计更简单、更简洁。
让我们举个例子。假设我正在编写某种需要在两个 API 之间同步某些业务对象的普通企业业务应用程序。这些 API 具有可以相互映射的对象模型,但使用不同的名称和不同的序列化格式。
在 PHP 中,多亏了抽象静态方法,我可以为这些业务对象类型定义一个抽象基类,看起来像这样......
abstract class ApiObject {
/** The REST resource URL for this object type in the Foo API. */
abstract static function fooApiResourceUrl();
/** The REST resource URL for this object type in the Bar API. */
abstract static function barApiResourceUrl();
/** Given an XML response from the Foo API representing an object of this
type, construct an instance. */
abstract static function fromFooXml($xml);
/** Given a JSON response from the Bar API representing an object of this
type, construct an instance. */
abstract static function fromBarJson($json);
/** Serialize this object in the XML format that the Foo API understands */
abstract function toFooXml();
/** Serialize this object as JSON that the Bar API understands */
abstract function toBarJson();
}
Run Code Online (Sandbox Code Playgroud)
...然后我创建的每个具体子类都将保证提供从两个 API 中的任何一个获取它并将其反序列化,或将其序列化并将其发送到任一 API 所需的所有信息。然后,稍后,我可以编写一些这样的代码:
// Ensure that all instances of these types that exist in the Foo API also
// exist in the Bar API:
$classesToSync = ['Widget', 'Frobnicator', 'Lead', 'Invoice'];
foreach ($classesToSync as $apiObjectClass) {
$fooObjXmls = httpGetRequest($apiObjectClass::fooApiResourceUrl());
foreach ($fooObjXmls as $fooObjXml) {
$fooObj = $apiObjectClass::fromFooXml($fooObjXml);
$json = $fooObj->toBarJson();
httpPutRequest($apiObjectClass::barApiResourceUrl(), $json);
}
}
Run Code Online (Sandbox Code Playgroud)
我是否严格需要抽象静态方法来编写上面的程序?不; 我还可以使用其他模式,例如让每个模型类与相应的工厂类配对,该工厂类负责从其 JSON 或 XML 表示中实例化它。但是这样的设计比我上面展示的设计更复杂。
那么,为什么允许它们的答案很简单,因为它们是有用的,因为它们启用了一些没有它们就不可能实现的漂亮、简单的模式。当然,也有反对它们存在的论据,其中一个在问题中给出 - 鉴于抽象类上的静态方法是可调用的,在类上公开抽象静态方法是丑陋的。我不认为这样的考虑特别有说服力,但即使你这样做,它们与抽象静态方法提供的实用程序之间仍然存在权衡,而且 PHP 维护者可能已经权衡了它们并选择了让抽象静态方法的一面存在。
| 归档时间: |
|
| 查看次数: |
5228 次 |
| 最近记录: |