首页 > 解决方案 > 我可以实现接口并覆盖接口方法之一的返回类型吗?

问题描述

我有一个Task扩展抽象类的类,TaskBase.

// class Task
class Task extends TaskBase {
   /**
    * @var Processor
    */
    private $processor

    public function __construct(Processor $processor) 
    {
        $this->processor = $processor;
    }

    public function process() : ProcessResult
    {
        return  $this->processor->execute();
    }
}

// abstract class TaskBase

abstract class TaskBase implements CommanTask {
    protected function getKey(): string
    {
    }
}

TaskBase实现了一个接口CommanTask,其中包含以下方法。

interface CommanTask {
  public function  process(): ProcessResult;
}

现在我需要一个新的任务类TaskMultiple,它的process()方法需要返回一个数组ProcessResult而不是一个ProcessResult

如何TaskBase为这个新类扩展抽象TaskMultiple类?

标签: phpoop

解决方案


如果你实现了一个接口,你需要真正遵守接口制定的契约。

您建议的界面说process()返回一个ProcessResult. 如果您可以在实现类中将其更改为返回array,则该类的使用者将无法信任接口指定的协定。

他们会尝试使用 的结果TaskMultiple::process(),并且由于他们的接口说它将返回 a ProcessResult,因此当它试图将其视为这样(例如,通过访问该类的方法)时,很快就会发生致命错误,但事实并非如此.

您的解决方案是:

如果您使用的是 PHP 8,则可以使用联合类型:

interface Task {
  public function  process(): ProcessResult|iterable;
}

它会工作,但它很丑陋。现在,任何Task实现服务的消费者都需要检查 的结果,process()看看它是单个ProcessResult还是一个集合(可能是ProcessResults)。

如果您使用的是 PHP < 8,则只需删除类型提示即可使其工作:

interface Task {
  public function  process()
}

现在消费者只知道有一个process()方法,但你根本没有类型信息。还是更丑。

更好的是,只需创建不同的接口,例如Taskand MultipleTask


interface Task {
  public function  process(): ProcessResult;
}


interface MultipleTask {
  public function  process(): iterable;
}

由于您BaseTask不包含任何有助于实现该类的内容(仅包含一个抽象方法,使其与接口非常相似),因此将implements移至每个具体任务类:

class ExampleTask extends BaseTask implements Task
{ /** implementation **/ }

class ExampleMultipleTask extends BaseTask implements MultipleTask
{ /** implementation **/ }

推荐阅读