为什么在PHP中无法从抽象类调用抽象函数?

53

我设置了一个抽象的父类和一个继承它的具体类。为什么父类不能调用抽象函数?

//foo.php
<?php
    abstract class AbstractFoo{
        abstract public static function foo();
        public static function getFoo(){
            return self::foo();//line 5
        }
    }

    class ConcreteFoo extends AbstractFoo{
        public static function foo(){
            return "bar";
        }
    }

    echo ConcreteFoo::getFoo();
?>

错误:

致命错误:在 foo.php 的第5行中,无法调用抽象方法 AbstractFoo::foo()


4
LOL... static abstract... :D: 是个很酷的问题。请问需要翻译什么呢? - Simon
3个回答

96

这是一个正确的实现;为了使用延迟静态绑定,您应该使用static而不是self:

abstract class AbstractFoo{
    public static function foo() {
        throw new RuntimeException("Unimplemented");
    }
    public static function getFoo(){
        return static::foo();
    }
}

class ConcreteFoo extends AbstractFoo{
    public static function foo(){
        return "bar";
    }
}

echo ConcreteFoo::getFoo();

返回预期的 "bar"。

请注意,这并不是真正的多态性。static关键字只是解析为调用静态方法的类。如果你声明了一个抽象的静态方法,你将会收到一个严格的警告。PHP会在子类中复制所有从父类继承而来的静态方法,如果子类中不存在这些方法的话。


2
生病了...谢谢!self和static有什么区别?编辑:显然这个关键字不存在(可能是版本问题)。 - Cam
1
是的,这仅适用于 PHP 5.3。 - Artefacto
LSB是使用PHP 5.3的主要原因。在设计模式中使用时,它比任何其他实现的功能都能节省更多的内存。 - Xeoncross
我遇到了一个 PHP 无法访问我的类中抽象静态方法实现的情况(在子类中实现) - 我用 "static::" 解决了这个问题。 - Buffalo
我从子类和抽象类中都删除了function旁边的static关键字。正确答案是return static::foo();。这样,超类就可以绑定到抽象函数的子类实现。PHP版本为5.6。 - daniel souza
显示剩余2条评论

8
你会注意到这里有一个词叫做self吗?它指向的是AbstractClass。因此它调用的是AbstractClass::foo(),而不是ConcreteClass::foo()。
我相信PHP 5.3将提供后期静态绑定,但如果你没有使用那个版本,self将不会引用扩展的类,而是函数所在的类。
参见:http://us.php.net/manual/en/function.get-called-class.php

1
在5.3+中,使用static关键字来引用ConcreteClass,而不是使用self关键字。 - philfreo

0

在编程中有一个规则,即不能同时在方法上使用abstractstatic关键字。

带有abstract关键字的方法意味着子类必须实现它。将static添加到类的方法中可以使我们在不实例化它的情况下使用该方法。

这就是为什么会出现错误的原因。


然而,它们可以被使用。一个例子是使用PHPUnit的静态setUpBeforeClass()方法,其值取决于子类 - 您需要一个抽象类(这样子类首先实现它并且不同),静态方法(这样您可以从setUpBeforeClass()中调用它)。 - Buffalo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接