";类X扩展了Y(抽象),Y实现了Z(接口)";无法调用接口Z”的抽象方法;


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

以下是我的PHP抽象类。最底层的类是将扩展抽象类并将一些复杂的计算逻辑留给父实现的类之一。

接口类(最顶层的抽象)的目的是强制那些较低的实现拥有自己的static public function id($params=false){方法。

// 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';
     }
}

最终结果是,如果我调用:

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

我得到一个致命错误:Fatal error: Cannot call abstract method MyInterface::id();

为什么MyAbstraction::run()调用其父(接口)的id()方法,而不是在其子(子)类中找到的方法?

  1. 接口中声明的所有方法都必须是公共的;这就是接口的本质。参考-PHP接口

  2. 您在MyAbstraction类中使用self::id()self总是引用同一个类。参考自身与静态

你应该使用static而不是self。请参阅以下代码。

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

在上面的代码中,static::id()将调用上下文中的类的函数,即MyImplementation类。

这种现象被称为后期静态绑定

"self"是对"MyAbstraction"类(本身)的引用。因此,它尝试搜索MyAbstraction::id(),但得到了一个错误。

  1. 你应该使用"static"关键字static::id();
  2. 不能在静态方法($this->id)中使用$this
  3. 您的所有方法都是静态的,因此不需要实例化对象。您可以使用静态调用执行同样的操作:MyImplementation::run();

尝试用static::id()替换您的self::id()

您可以在这里使用PHP的Late静态绑定。