Заставить один интерфейс перезаписывать метод, который он наследует от другого интерфейса в PHP - PullRequest
2 голосов
/ 19 августа 2008

Есть ли в 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, в таблице «Vendors», что означает, что он получает все свойства каждого другого поставщика, но нуждается в дополнительных свойствах и методах, предоставляемых iShipper).

Ответы [ 2 ]

6 голосов
/ 19 августа 2008

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

EDIT:

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

A. У каждого интерфейса больше нет метода конструктора.
B. Все грузоотправители (UPS, FedEx и т. Д.) Теперь реализуют iShipper (который расширяет iVendor) и расширяют абстрактный класс Shipper (в котором определены все общие неабстрактные методы для грузоотправителей, getName (), getZip () и т. Д.).
C. У каждого грузоотправителя есть свой уникальный метод _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...
}

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

0 голосов
/ 19 августа 2008

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

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

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

abstract class Shipper implements iShipper {
    public function __construct() {
        something();
    }
}
...