简体   繁体   中英

“Class X extends Y (abstract), Y implements Z (interface). ”Cannot call abstract method of interface Z"

Here are my PHP abstraction classes. The bottom most class is one of the classes that will extend the abstract class and leave some of the complex calculation logic to the parent implementation.

The point of the interface class (the top most abstraction) is to force those lower implementations have their own static public function id($params=false){ method.

// My top level abstraction, to be implemented only by "MyAbstraction"
interface MyInterface{
      static public function id();
}

// My second (lower) level of abstraction, to be extended
// by all child classes. This is an abstraction of just the
// common heavy lifting logic, common methods and properties.
// This class is never instantiated, hence the "abstract" modifier.
// Also, this class doesn't override the id() method. It is left
// for the descendant classes to do.

abstract class MyAbstraction implements MyInterface{

    // Some heavy lifting here, including common methods, properties, etc
    // ....
    // ....

     static public function run(){
          $this->id = self::id(); // This is failing with fatal error
     }
}

// This is one of many "children" that only extend the needed methods/properties
class MyImplementation extends MyAbstraction{

     // As you can see, I have implemented the "forced"
     // method, coming from the top most interface abstraction
     static public function id(){
         return 'XXX';
     }
}

The end result is that if I call:

$o = new MyImplementation();
$o->run();

I get a fatal error: Fatal error: Cannot call abstract method MyInterface::id();

Why is MyAbstraction::run() calling the id() method of its parent (interface) instead of the method found in its child (descendant) class?

  1. All methods declared in an interface must be public; this is the nature of an interface. Reference - PHP interface

  2. You are using self::id() in MyAbstraction class, self always refers same class. reference self vs static

you should use static instead of self. Refer below code.

interface MyInterface{
    public function id();
}

abstract class MyAbstraction implements MyInterface{

    public $id;
    // Some heavy lifting here, including common methods, properties, etc
    // ....
    // ....

    public function run(){
        $this->id = static::id(); // This is failing with fatal error
    }
}

class MyImplementation extends MyAbstraction{

    // As you can see, I have implemented the "forced"
    // method, coming from the top most interface abstraction
    public function id(){
        return 'XXX';
    }
}

$o = new MyImplementation();
$o->run();

In above code static::id() will call function of class which is in context ie MyImplementation class.

This phenomenon known as Late Static Binding

"self" is reference to "MyAbstraction" class (itself). So it try to search MyAbstraction::id() , and got an error.

  1. You shoud use "static" keyword static::id();
  2. You cannot use $this in static method ($this->id) .
  3. All of your methods are static, so You do not need instantiate an object. You can do the same with a static call: MyImplementation::run();

Try to replace your self::id() by static::id() .

You use the Late Static Bindings of PHP here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM