53

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

Cam
  • 14,930
  • 16
  • 77
  • 128

3 Answers3

94

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
  • 96,375
  • 17
  • 202
  • 225
  • 2
    Sick... Thanks! What is the difference between self and static? Edit: Apparently that keyword does not exist (might be a version thing). – Cam May 18 '10 at 17:58
  • 1
    Yes, this is only available on PHP 5.3. – Artefacto May 18 '10 at 18:05
  • LSB is the main reason to use PHP 5.3. It saves more memory than any other feature implemented when used in design patterns. – Xeoncross Jun 21 '11 at 17:40
  • I had a case of PHP failing to reach the implementation of a abstract static method in my class (implemented in a subclass) - solved it with "static::". – Buffalo Jan 19 '17 at 13:07
  • I removed the `static` word next to `function` from both child and abstract classes. `return static::foo();` whas the correct answer. So the superclass can bind to the child class implementation of abstract function. PHP version 5.6. – daniel souza Dec 06 '17 at 03:21
  • Thank you for that! – Severin May 15 '19 at 20:18
  • Interface function App\Repositories\Banner\BannerRepository::foo() cannot contain body – saber tabatabaee yazdi Aug 05 '20 at 06:23
8

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

Tyler Carter
  • 60,743
  • 20
  • 130
  • 150
0

It's a rule that abstract and static keywords can not be use on a method at the same time.

A method with an abstract keyword means that sub-class must implement it. Adding static to a method of a class allows us to use the method without instantiating it.

So that is why the error occurs.

Mike G
  • 746
  • 5
  • 19
Tomheng
  • 11
  • 1
  • And, yet, they can be used. An example would be using PHPUnit's static setUpBeforeClass() with values depending on subclasses - you'd need an abstract (so the subclasses implement it in the first place and also differently) static (so you can call it from setUpBeforeClass()) method. – Buffalo Jan 19 '17 at 13:09