Заставить один интерфейс перезаписать метод, который он наследует от другого интерфейса в PHP.

StackOverflow https://stackoverflow.com/questions/16155

  •  08-06-2019
  •  | 
  •  

Вопрос

Есть ли в PHP способ перезаписать метод, объявленный одним интерфейсом, в интерфейсе, расширяющем этот интерфейс?

Пример:

Наверное я что-то делаю не так, но у меня вот что:

interface iVendor{
    public function __construct($vendors_no = null);
    public function getName();
    public function getVendors_no();
    public function getZip();
    public function getCountryCode();
    public function setName($name);
    public function setVendors_no($vendors_no);
    public function setZip($zip);
    public function setCountryCode($countryCode);
}

interface iShipper extends iVendor{
    public function __construct($vendors_no = null, $shipment = null);
    public function getTransitTime($shipment = null);
    public function getTransitCost($shipment = null);
    public function getCurrentShipment();
    public function setCurrentShipment($shipment);
    public function getStatus($shipment = null);
}

Обычно в PHP, когда вы что-то расширяете, вы можете перезаписать любой содержащийся в нем метод (верно?).Однако когда один интерфейс расширяет другой, это вам не позволит.Если только я не думаю об этом неправильно...Когда я реализую интерфейс iShipper, мне не нужно расширять объект Shipper объекта Vendor (который реализует интерфейс iVendor).Я просто говорю:

class FedEx implements iShipper{}

и заставить FedEx реализовать все методы iVendor и iShipper.Однако мне нужно __construct функции в iVendor и iShipper должны быть уникальными.Я знаю, что могу вынуть $shipment = null, но тогда было бы не так удобно создавать отправителей (просто передаваяvendors_no и отгрузку при создании экземпляра).

Кто-нибудь знает, как заставить это работать?Мой запасной вариант - договориться об отправке, позвонив $shipper->setShipment($shipment); на отправителе после того, как я создам его экземпляр, но я надеюсь на способ обойти эту необходимость...

Еще немного пояснений для любопытных:
Объект FedEx имеет методы, которые переходят на сайт FedEx (используя cURL) и получают оценку рассматриваемой отправки.У меня есть объект UPS, объект BAXGlobal, объект Conway и т. д.У каждого из них есть ПОЛНОСТЬЮ разные методы для фактического получения оценки доставки, но все, что системе нужно знать, это то, что они являются «отправителями» и что методы, перечисленные в интерфейсе, могут быть вызваны для них (поэтому она может обращаться со всеми ними совершенно одинаково). и перебираем их в массиве "отправителей", вызывая getTransitX() чтобы найти лучшего грузоотправителя для груза).

Однако каждый «Отправитель» также является «Продавцом» и рассматривается как таковой в других частях системы (получение и размещение в БД и т. д.).Наш дизайн данных — это куча дерьма, поэтому FedEx хранится рядом с такими компаниями, как Dunder Mifflin, в таблице «Поставщики», что означает, что он имеет все свойства любого другого поставщика, но нуждается в дополнительных свойствах и методах, предоставляемых iShipper. ).

Это было полезно?

Решение

@cmcculloh Да, в Java вы не определяете конструкторы в интерфейсах.Это позволяет вам как расширять интерфейсы, так и иметь класс, реализующий несколько интерфейсов (оба разрешены и очень полезны во многих случаях), не беспокоясь о необходимости удовлетворения конкретного конструктора.

РЕДАКТИРОВАТЬ:

Вот моя новая модель:

А.Каждый интерфейс больше не имеет метода-конструктора.
Б.Все грузоотправители (UPS, FedEx и т. д.) теперь реализуют iShipper (который расширяет iVendor) и расширяют абстрактный класс Shipper (в котором определены все распространенные неабстрактные методы для грузоотправителей, getName(), getZip() и т. д.).
С.У каждого грузоотправителя есть свой собственный уникальный метод _construct, который перезаписывает абстрактный метод __construct($vendors_no = null, $shipment = null), содержащийся в грузоотправителе (хотя я не помню, почему я теперь разрешаю им быть необязательными.Мне придется вернуться к своей документации...).

Так:

interface iVendor{
    public function getName();
    public function getVendors_no();
    public function getZip();
    public function getCountryCode();
    public function setName($name);
    public function setVendors_no($vendors_no);
    public function setZip($zip);
    public function setCountryCode($countryCode);
}

interface iShipper extends iVendor{
    public function getTransitTime($shipment = null);
    public function getTransitCost($shipment = null);
    public function getCurrentShipment();
    public function setCurrentShipment($shipment);
    public function getStatus($shipment = null);
}

abstract class Shipper implements iShipper{  
    abstract public function __construct($vendors_no = null, $shipment = null);  
    //a bunch of non-abstract common methods...  
}

class FedEx extends Shipper implements iShipper{  
    public function __construct($vendors_no = null, $shipment = null){
        //a bunch of setup code...
    }
    //all my FedEx specific methods...
}

Спасибо за помощь!
пс.поскольку я добавил это к «вашему» ответу, если вам что-то не нравится/считаете, что в этом должно быть что-то другое, не стесняйтесь изменить это...

Другие советы

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

Я думаю, вам нужно создать абстрактный класс, реализующий поставщика, и класс, реализующий грузоотправителя.Там вы можете определить конструкторы по-другому.

abstract class Vendor implements iVendor {
    public function __construct() {
        whatever();
    }
}

abstract class Shipper implements iShipper {
    public function __construct() {
        something();
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top