tags:

views:

64

answers:

4
abstract class base {
    abstract public function test();
    public function run()
    {
        self::test();
    }
}

class son extends base {
    public function test()
    {
        echo 1;
    }
}
son::run();

It reports:

Fatal error: Cannot call abstract method base::test()

But son::test() works,why and is there a way to fix?

+1  A: 

Abstract methods do not have an implementation, and thus cannot be called. If the method is not defined as abstract, and actually has an implementation, then it can be executed by your code. For example:

public function test(){
    echo "Hello from base!";
}
Justin Ethier
My question is how to make it point to the child class if available?
+4  A: 

Of course:

Fatal error: Cannot call abstract method base::test()

It has no method body you could call. If run() is supposed to be a Template Method, you refer to the class scope with $this instead of self and then create an instance of $son to call run() on it, e.g.

abstract class BaseClass {
    abstract public function test();
    public function run()
    {
        $this->test();
    }
}

class Son extends BaseClass {
    public function test()
    {
        echo 1;
    }
}

$son = new Son;
$son->run(); // 1

which is rather odd, because then you could have just as well called test() directly.

Also note that in your example

son::run();

is wrong, because the run() method is not declared static and while PHP will execute run() nonetheless, it is considered wrong usage and will raise an E_STRICT error. However, if you were to define run() static, you could no longer reference $this, because a static method is not invoked from instance scope, but class scope.

Edit I was about to add the PHP5.3 solution, but see that @stereofrog already did that, while I was typing, so I only add the appropriate reference in the PHP Manual on Late Static Binding.

Gordon
I don't want to do instantiation:(How to make it point to the child class without new instance?
@user198729 why not?
Gordon
Because the requirement is just to point to the child class,do you mean it's necessary to new an instance to do this kind of thing?
@user198729 Necessary? Well, that depends on the UseCase. Static methods sure have their uses, but are generally frowned upon in an OO context. See http://www.phparch.com/2010/03/03/static-methods-vs-singletons-choose-neither/
Gordon
Don't try to be pure OOP when you are using PHP,this is what I learned these days by using symfony/doctrine,both latest version...:(
+3  A: 

"self" is lexically scoped, that is, if you use "self" in a method of Base, "self" means "Base", no matter how you call this method at run time. php5.3 introduced a new kind of dynamic binding, which, ironically enough, is called "static". The following works as expected in php 5.3

abstract class base {
    abstract public static function test();
    static public function run()
    {
        static::test();
    }
}

class son extends base {
    static public function test()
    {
        echo 1;
    }
}
son::run();
stereofrog
Great,works!It's indeed ironical to name a dynamic feature "static"!
+1  A: 

Factory/singleton pattern mix:

class Base
{
    static private $instance;

    static function getSon() {
        if (null === self::$instance) {
            self::$instance = new Son;();
        }

        return self::$instance;
    }
}

class Son
{
    public function test() {
        echo 1;
    }
}

Base::getSon()->test(); //1
erenon