为什么PHP5.2+;不允许抽象静态类方法?
在PHP 5.2中启用严格警告后,我看到一个项目中出现了大量严格标准警告,该项目最初是在没有严格警告的情况下编写的: 严格标准:静态函数Program::getSelectSQL()在Program.class.inc中不应是抽象的 该函数属于抽象父类程序,并被声明为抽象静态函数,因为它应该在其子类(如TVProgram)中实现 我确实找到了这一变化的参考: 删除了抽象静态类函数。由于疏忽,PHP5.0.x和5.1.x允许在类中使用抽象静态函数。从PHP5.2.x开始,只有接口可以拥有它们为什么PHP5.2+;不允许抽象静态类方法?,php,oop,static,abstract,Php,Oop,Static,Abstract,在PHP 5.2中启用严格警告后,我看到一个项目中出现了大量严格标准警告,该项目最初是在没有严格警告的情况下编写的: 严格标准:静态函数Program::getSelectSQL()在Program.class.inc中不应是抽象的 该函数属于抽象父类程序,并被声明为抽象静态函数,因为它应该在其子类(如TVProgram)中实现 我确实找到了这一变化的参考: 删除了抽象静态类函数。由于疏忽,PHP5.0.x和5.1.x允许在类中使用抽象静态函数。从PHP5.2.x开始,只有接口可以拥有它们 我的
我的问题是:有人能清楚地解释为什么PHP中不应该有抽象的静态函数吗?静态方法属于声明它们的类。扩展类时,可以创建同名的静态方法,但实际上并不是实现静态抽象方法 使用静态方法扩展任何类也是如此。如果扩展该类并创建具有相同签名的静态方法,则实际上并没有重写超类的静态方法 编辑(2009年9月16日)
这方面的最新情况。运行PHP5.3,无论好坏,我看到抽象静态代码又回来了。(有关更多信息,请参阅) 更正(由philfreo提供)
抽象静态
在PHP5.3中仍然是不允许的,它是相关的,但不同。我认为抽象类/接口可以看作是程序员之间的契约。它更多地处理事物的外观/行为,而不是实现实际的功能。正如在php5.0和5.1.x中所看到的那样,阻止php开发人员这样做并不是一条自然规律,而是与其他语言中的其他OO设计模式一起使用的冲动。基本上,如果你已经熟悉其他语言,这些想法试图防止意外行为。研究PHP的“后期静态绑定”问题。如果你把静态方法放在抽象类上,你很可能很快就会遇到它。严格的警告告诉您避免使用损坏的语言功能是有道理的。我知道这很旧,但
为什么不在父类的静态方法中抛出一个异常呢?如果不重写它,那么异常就是由它引起的。对于这个问题,有一个非常简单的解决方法,从设计的角度来看,这实际上是有意义的。乔纳森写道: 使用静态方法扩展任何类也是如此。如果扩展该类并创建具有相同签名的静态方法,则实际上并没有重写超类的静态方法 因此,作为一项工作,您可以这样做:
<?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();
}
?>
我不认为有任何理由禁止静态抽象函数。没有理由禁止它们的最佳论据是,它们在Java中是允许的。
问题是:
-技术上可行吗?-是的,因为它们存在于PHP5.2中,并且存在于Java中。
那么,谁能做到这一点呢。我们应该这样做吗?
-它们有意义吗?对实现类的一部分并将类的另一部分留给用户是有意义的。它在非静态函数中是有意义的,为什么它不应该在静态函数中有意义呢?静态函数的一种用法是类中不能有多个实例(单例)。例如,加密引擎。它不需要存在于多个实例中,并且有理由防止这种情况发生——例如,您只需要保护内存的一部分以防入侵者。因此,实现引擎的一部分并将加密算法留给用户是非常有意义的。
这只是一个例子。如果您习惯于使用静态函数,您会发现更多。在PHP5.4+中使用trait:
trait StaticExample {
public static function instance () {
return new self;
}
}
在你的课堂上,在乞讨课上:
use StaticExample;
这是一个漫长而悲伤的故事
当PHP5.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();
拉斯姆斯
对,这正是它应该如何工作的
乔治
但这是不允许的:(
拉斯姆斯
什么是不允许的
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)已经从PHP7语言中删除了警告。最终,理智占了上风,一旦PHP7发布,我们都可以愉快地使用abstract static
,而不会收到这个愚蠢的警告。好的,那么如果我想强制执行函数getSelectSQL()的需要呢在扩展我的抽象类的所有子类中?父类中的getSelectSQL()没有存在的有效理由。最佳行动计划是什么?我选择抽象静态的原因是,在我在所有子类中实现getSelectSQL()之前,代码不会编译。最有可能的是,您应该重新设计getSelectSQL()是一个抽象/实例/方法。这样,每个子级的/instances/都会有这样一个方法。抽象静态在PHP5.3中仍然是不允许的。后期的静态绑定与此无关。我认为这个严格的警告是愚蠢的
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();