views:

319

answers:

3

I've set up an abstract parent class, and a concrete class which extends it. Why can the parent class not call the abstract function?

//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();
?>

Error:

Fatal error: Cannot call abstract method AbstractFoo::foo() in foo.php on line 5


EDIT: @Simon's Answer - Then why does this work? ... (answer removed)

+3  A: 

You notice that word self?

That is pointing to AbstractClass. Thus it is calling AbstractClass::foo(), not ConcreteClass::foo();

I believe PHP 5.3 will provide late static bindings, but if you are not on that version, self will not refer to an extended class, but the class that the function is located in.

See: http://us.php.net/manual/en/function.get-called-class.php

Chacha102
A: 

Because abstract class methods don't have a definition. They are declared to exist in the class, but don't have a definition - not even an empty one. Same goes with trying to create objects out of abstract classes. Even if you call a concrete method of an abstract class, if that method itself calls an abstract static method, as in your example:

public static function getFoo(){
    return self::foo();
}

Then it won't work.

In the case of overriding the abstract method to make it concrete, you can call the subclass's override of the same method, because now the method has a definition, which in your example is:

public static function foo(){
    return "bar";
}

Therefore calling ConcreteFoo::foo() gives 'bar'.

BoltClock
+8  A: 

This is a correct implementation; you should use static, not self, in order to use late static bindings:

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();

gives the expected "bar".

Note that this is not really polymorphism. The static keywork is just resolved into the class from which the static method was called. If you declare an abstract static method, you will receive a strict warning. PHP just copies all static methods from the parent (super) class if they do not exist in the child (sub) class.

Artefacto
Sick... Thanks! What is the difference between self and static? Edit: Apparently that keyword does not exist (might be a version thing).
Cam
Read the manual page on late static bindings that I linked.
Artefacto
Yes, this is only available on PHP 5.3.
Artefacto