为什么PHP5.2+;不允许抽象静态类方法?

为什么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 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();