Правильно ли я понял, что интерфейс можно использовать тогда, когда в конкретный класс, надо поместить все методы, которые нужны, из других классов, но так не получится, потому что класс наследуется, только от одного класса. А когда есть несколько интерфейсов и в них разные методы, то эти методы, можно пораскидать по разным классам, а потом уже унаследовать все нужные методы из разных классов, через implements и названия интерфейсов.
Интерфейс - это контракт. Если у вас есть несколько разных классов, которые делают одно и тоже, но разными способами, то вам нужны интерфейсы. Типичный пример - это работа с файловой системой: 1. ФС может быть физически расположена на той же машине (либо примонтирована) и работать с ней можно обычными способами ОС. 2. ФС может быть удаленной, лежать где-нибудь на S3 или доступна только по sftp 3. Что-то ещё, возможно даже экзотическое. В таких случаях вы создаете интерфейс, где описаны публичные методы (название, что передает, что возвращает) и каждой реализации его имплементируете. Важно понимать, что сам по себе он не делает ничего, он нужен лишь для уверенности программиста в том, что вот эта вот реализация работает внешне точно так, у неё есть определенный набор методов и подменив какой-нибудь LocalFS на SFTPFS не придется переписывать половину проекта. Не удивлюсь, если скоро понабегут и начнут рассказывать, что все это излишество и никому не нужно. Действительно, то что работает с интерфейсами сможет точно так же работать и без них. Это просто правило хорошего тона и дополнительная проверка, что бы проще было через полгода разгребать свою же простынку или разобраться в чужой ) А то про что вы писали судя по всему - трейты )
https://github.com/thephpleague/flysystem/blob/master/src/AdapterInterface.php https://github.com/thephpleague/flysystem/tree/master/src/Adapter ну или совсем на пальцах: PHP: <?php interface MultiplicateThis { public function multiplicate(int $a, int $b) : int; } class Addition implements MultiplicateThis { public function multiplicate(int $a, int $b): int { $response = 0; for($i = 1; $i <= $b; $i++) { $response += $a; } return $response; } } class Multiplication implements MultiplicateThis { public function multiplicate(int $a, int $b): int { return $a * $b; } } class Test { protected $adapter; public function __construct(MultiplicateThis $adapter) { $this->adapter = $adapter; } public function run() { $a = rand(0, 100); $b = rand(0, 100); echo "a: $a".PHP_EOL; echo "b: $b".PHP_EOL; $result = $this->adapter->multiplicate($a, $b); echo "result: $result".PHP_EOL; if ($result === $a * $b) { echo "yeah!".PHP_EOL; } else { echo "wtf?".PHP_EOL; } } } (new Test(new Addition()))->run(); (new Test(new Multiplication()))->run();
Правильно ли я использовал интерфейс? PHP: <?php header('Content-Type: text/html; charset=utf-8'); interface GetPriceProduct{ public function getPrice(); } class Product{ protected $name; protected $price; function __construct($name, $price){ $this->name = $name; $this->price = $price; } } class Pasta extends Product implements GetPriceProduct{ public function getPrice(){ return $this->price; } } $makaron = new Pasta('Макароны', 200); echo $makaron->getPrice(); --- Добавлено --- то есть интерфейс удобно использовать тогда, когда метод принимает одинаковое количество аргументов и делает с ними разные вещи? --- Добавлено --- В вашем примере, почему-то ругается на двоеточие PHP: public function multiplicate(int $a, int $b) : int;
Скорее когда делает одни и те же вещи, но разными способами. Важно что всю логику ты прячешь где-то там, за интерфейсом, который знает остальная часть приложения и работает исключительно с ним. Будут ли $a и $b сразу перемножаться, складываться или стучаться в гугл за ответом - вопрос реализации, приложение же знает, что если класс реализует этот интерфейс, то всегда можно дернуть метод с двумя целыми числами и получить результат. В целом - да, правильно. Теперь в том месте, где нужно работать с ценой товара, ты можешь просто проверить на интерфейс и не важно, паста это или отбойный молоток, хранится ли цена в базе или дергается из xml скаченного с яндекс-маркета. Тут главное не переборщить и не лепить интерфейсы куда попало. Это хелпер, что бы случайно не поменять что-то, от чего отвалится половина приложения. Изменил метод, который описан в интерфейсе, пых сразу отвалился с ошибкой и сиди думай что дальше делать )) --- Добавлено --- это в PHP7 добавили.
Интерфейс можно рассматривать как абстрактный класс без полей, и без реализованных методов. Плюс интерфейсы в некотором роде замена множественного наследования - т.е. класс может реализовывать несколько интерфейсов. В твоём примере ты вообще никак не используешь преимущества от интерфейсов. Это всё в продолжении темы полиморфизма, которую ты не чувствуешь явно. Вот если брать даже твой пример: PHP: interface HasPrice { function getPrice(); } class Product implements HasPrice { private $price; function __construct($price) {$this->price = $price } function getPrice() { return $this->price; } } class Collection implements HasPrice { /** @var HasPrice[] */ private $products; /** * @param HasPrice[] $products */ public function __construct(array $products) { $this->products = $products; } public function getPrice() { $sum = 0; foreach ($this->products as $p) { $sum += $p->getPrice(); } return $sum; } } function printPrice(HasPrice $product) { echo "Цена " . $product->getPrice() . "<br>"; } $p1 = new Product(12); $p2 = new Product(25); $p3 = new Product(57); $c1 = new Collection([$p1, $p2]); $c2 = new Collection([$c1, $p3]); printPrice($p1); printPrice($c1); printPrice($c2); Потому что у тебя не седьмой php
если какой-нибудь пример кода одной задачи, которая решена с помощью интрефейсов, а друга без? и увидеть в чём же приемущество
@Dimon2x, я же тебе показал вполне нормальный код. Хотя короткий пример очень трудно придумать. Вот посмотри мой код. Функция printPrice() понятия не имеет, какой объект в неё будет передан. Главное, чтоб он реализовывал интерфейс HasPrice, в котором определён метод getPrice(). В неё я передаю сначала экземпляр Product, в котором getPrice() просто возвращает значение поля price(), а потом передаю экземпляр Collection, где getPrice() уже делает куда больше - суммирует все объекты в коллекции. Это один пример использования интерфейсов. Второй пример - это класс Collection. В нём можно объединять экземпляры любых классов, реализующих HasPrice, и он будет считать сумму. Его функция getPrice() вызывает getPrice() объектов внутри коллекции и суммирует их. Обрати внимание, что каждый элемент коллекции может быть экземпляром любого класса, реализующего HasPrice, в том числе и другой коллекцией, как в объекте $c2. Смысл в том, чтобы писать функции, которые не зависят от конкретной реализации класса с ценой, они лишь должны содержать реализацию интерфейса. Сюда можно было добавить ещё класс Service, описывающий услугу, и тогда можно было бы описывать коллекции из услуг и товаров. И функция printPrice() всегда будет верно выводить цену (при условии, что верна реализация getPrice()).
Автор, гляди. Есть вот Камаз, Жигули и Болид F1. Это крайне разные машины. По-разному устроены. Для разных целей сделаны. Отличия в характеристиках колоссальные. Но...у них есть общий интерфейс вида "руль,педали". И человеку, в общем-то не надо знать, как сделана та или иная машина. Он знает интерфейс "руль, педали", и знает, что если крутить рулем, машина будет входить в поворот. А педали отвечают за ускорение и торможение. Грубенько, но суть дает. Интерфейсом, неявно, может служить родительский класс, при условии, что только наследуемые свойства и методы будут использоваться у потомков. Но, дело в том, что никто никогда не запрещал реализовывать одинаковый набор методов в независимых друг от друга классах без общего предка. При этом наследование от общего предка может быть в принципе невозможно из-за разницы реализации. Вот по этому и придумали в ООП интерфейсы. Наследуясь от интерфейсов ты просто как бы говоришь приложению, что гарантируешь работоспособность таких-то методов, и что возвращаемые ими значения будут такими, какие ожидается. Так, к примеру, работают всякие моддинговые API в играх. Тебе никто не даст исходники игры, чтоб ты там от чего-то наследовался. Держи карман шире. А вот интерфейсы - запросто. В итоге твоя dll-ка будет без проблем общаться с ядром игры.