Тип Подсказка для нескольких несвязанных интерфейсов - PullRequest
7 голосов
/ 02 марта 2011

Есть ли в php способ напечатать подсказку для двух разных, не связанных интерфейсов? Например:

interface errorable {
   function error($msg);
}

interface recordable {
   ssh_for_recorder();
}

class uploader__module extends base__module implements errorable, recordable {
   public function ssh_for_recorder() {
      return new ssh2;
   }
   public function error($msg) {
      $this->errors[] = $msg;
   }

   public function upload() {
      $recorder = new recorder($this);
      $recorder->run();
   }
}

class recorder {
   private $ssh2;
   private $module;
   private function upload() {
      if (!$this->ssh2) {
         $this->module->error("No SSH2 connection");
      }
   }
   public function __construct({recordable,errorable} $module) {
      $this->module = $module;
      $this->ssh2 = $module->ssh_for_recorder();
   }
}

Как вы можете видеть в приведенном выше коде, класс устройства записи ожидает, что его модуль сможет запускать как error(), так и ssh_for_recorder(), но они определяются различными интерфейсами. ошибка не должна быть записываемой и наоборот.

Есть ли лучшая практика для этого? Я думал о создании интерфейса, который расширяется от записываемых и ошибочных, и о том, чтобы выгрузка реализовывала модуль загрузки, но я не знаю, как его назвать.

Ответы [ 4 ]

10 голосов
/ 02 марта 2011

Нет, это не возможно в php.

Существуют другие языки (в основном функциональные), которые поддерживают эту функцию, которая называется типом объединения (http://en.wikipedia.org/wiki/Sum_type).

6 голосов
/ 02 марта 2011

Единственный хак в PHP - это вспомогательная функция, которая выполняет проверки для вас внутри метода следующим образом:

function CheckInterfaces($object,array $interfaces)
{
    foreach($interfaces as $i)
    {
         if(!is_a($object,$i))
         {
             return false;
         }
    }
    return true;
}

А затем внутри метода выполните:

public function Something($object)
{
    if(CheckInterfaces($object,array("foo","bar")))
    {
        throw new ArgumentException(gat_class($object) . " Must be a member of foo,bar to be passed to Something");
    }
}

другойметод обойти эту проблему, например, создать интерфейс объединения для ваших необходимых интерфейсов, вот быстрый пример

interface foobar extends foo,bar{}

, тогда вы можете просто потребовать foobar для метода.

2 голосов
/ 22 августа 2016

Я решил ответить на этот вопрос, даже если вы уже приняли ответ на том основании, что ни один из приведенных ответов не является приемлемым. Хотя принятый ответ является технически правильным, есть способ обойти его. Что касается других ответов, их обходные пути не элегантны и не вполне удовлетворительны.

PHP поддерживает довольно непонятную функцию, которая позволяет одному интерфейсу наследоваться от другого, и фактически интерфейс способен наследовать от нескольких базовых интерфейсов.

Например, следующее совершенно верно:

interface iFoo
{
    public function doFoo ();
}

interface iBar
{
    public function doBar ();
}

interface iBaz extends iFoo, iBar
{
    // This interface implicitly has all the methods of iFoo and iBar
}

Семантически, если вы хотите, чтобы метод / функция принимал только аргумент, который реализует несколько интерфейсов, то это, как правило, предполагает, что вы ожидаете, что классы, которые реализуют один и тот же набор нескольких интерфейсов, на самом деле должны реализовывать интерфейс, который охватывает оба интерфейсы, которым вы хотите, чтобы ваш аргумент соответствовал.

В вашем случае, если вы хотите что-то, что является ошибочным и записываемым, вам просто нужно добавить следующий интерфейс:

interface RecordableErrorable extends Recordable, Errorable { }

И тогда конструктор для вашего класса Recorder просто ожидает, что этот интерфейс будет использоваться в качестве аргумента.

public function __construct(RecordableErrorable $module) { }

Одним из возможных препятствий может быть, если Recordable и Errorable оба реализуют методы с одинаковыми именами. Там будет столкновение, которое нужно будет решить. Я верю, что в PHP есть механизмы для обработки этого случая, хотя я не могу сказать вам, что это такое.

0 голосов
/ 10 апреля 2015
public function __construct(recordable $recordable_module, errorable $errorable_module) {

  if($recordable_module == $errorable_module){
     $module = $recordable_module;
  }
  $this->module = $module;
  $this->ssh2 = $module->ssh_for_recorder();
}
...