Art*_*kii 120 php oop static abstract
在PHP 5.2中启用严格警告后,我看到一个项目的严格标准警告,这些警告最初是在没有严格警告的情况下编写的:
严格标准:静态函数 Program :: getSelectSQL()在Program.class.inc中不应该是抽象的
有问题的函数属于抽象父类Program,并被声明为abstract static,因为它应该在其子类中实现,例如TVProgram.
我确实在这里找到了对此更改的引用:
删除了抽象的静态类函数.由于疏忽,PHP 5.0.x和5.1.x允许在类中使用抽象静态函数.从PHP 5.2.x开始,只有接口才能拥有它们.
我的问题是:有人可以清楚地解释为什么在PHP中不应该有一个抽象的静态函数?
Jon*_*and 76
静态方法属于声明它们的类.扩展类时,您可以创建一个同名的静态方法,但实际上并不是实现静态抽象方法.
使用静态方法扩展任何类都是一样的.如果扩展该类并创建相同签名的静态方法,则实际上并未覆盖超类的静态方法
编辑(2009年9月16日)
更新.运行PHP 5.3,我看到抽象静态回来了,无论好坏.(有关详细信息,请参阅http://php.net/lsb)
abstract static在PHP 5.3中仍然不允许CORRECTION(由philfreo),LSB是相关但不同的.
Mar*_*ery 75
这是一个漫长而悲伤的故事.
当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();
Run Code Online (Sandbox Code Playgroud)
抛开严格模式警告,上面的代码不起作用.该self::bar()呼叫foo()明确提到bar()的方法ParentClass,即使在foo()被称为的方法ChildClass.如果您尝试在严格模式下运行此代码,您将看到" PHP致命错误:无法调用抽象方法ParentClass :: bar() ".
鉴于此,PHP 5.2中的抽象静态方法毫无用处.使用抽象方法的全部意义在于,您可以编写调用方法的代码,而无需知道它将调用哪个实现 - 然后在不同的子类上提供不同的实现.但是,由于PHP 5.2没有提供编写父类的方法的简洁方法,该方法调用调用它的子类的静态方法,因此无法使用抽象静态方法.因此abstract static,PHP 5.2中的任何使用都是错误的代码,可能是由于对self关键字如何工作的误解所致.对此发出警告是完全合理的.
但是随后PHP 5.3增加了引用通过static关键字调用方法的类的能力(与self关键字不同,关键字总是指定义方法的类).如果您更改self::bar()到static::bar()在我上面的例子,它工作在PHP 5.3及以上的罚款.你可以在New self和new static上阅读更多关于selfvs的内容.static
添加静态关键字后,abstract static抛出警告的明确参数消失了.后期静态绑定的主要目的是允许父类中定义的方法调用将在子类中定义的静态方法; 鉴于存在后期静态绑定,允许抽象静态方法似乎是合理且一致的.
我想,你仍然可以提出保持警告的理由.例如,您可以争辩说,因为PHP允许您调用抽象类的静态方法,在上面的示例中(即使在通过替换self来修复它之后static),您暴露了一个ParentClass::foo()被破坏的公共方法,并且您并不真正想要暴露.使用非静态类 - 即,使所有方法实例方法并使所有方法ParentClass成为单例或其他东西 - 将解决此问题,因为ParentClass,是抽象的,无法实例化,因此其实例方法不能叫做.我认为这个论点很弱(因为我觉得暴露ParentClass::foo()并不是什么大问题,使用单身而不是静态类通常是不必要的冗长和丑陋),但你可能会合理地反对 - 这是一个有点主观的呼吁.
所以基于这个论点,PHP开发人员用语言保留了警告,对吧?
呃,不完全是.
上面链接的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而不会收到这个愚蠢的警告.
Wou*_*iet 70
对于这个问题,有一个非常简单的方法,从设计的角度来看,这实际上是有意义的.正如乔纳森所写:
使用静态方法扩展任何类都是一样的.如果扩展该类并创建相同签名的静态方法,则实际上并未覆盖超类的静态方法
所以,作为一个解决方法你可以做到这一点:
<?php
abstract class MyFoo implements iMyFoo {
public static final function factory($type, $someData) {
// don't forget checking and do whatever else you would
// like to do inside a factory method
$class = get_called_class()."_".$type;
$inst = $class::getInstance($someData);
return $inst;
}
}
interface iMyFoo {
static function factory($type, $someData);
static function getInstance();
function getSomeData();
}
?>
Run Code Online (Sandbox Code Playgroud)
现在,您强制执行任何子类化MyFoo的类实现getInstance静态方法和公共getSomeData方法.如果你不是MyFoo的子类,你仍然可以实现iMyFoo来创建一个具有类似功能的类.
Pet*_*tah 12
我知道这已经过时了......
为什么不抛出那个父类的静态方法的异常,这样如果你不覆盖它就会导致异常.