За последние 24 часа нас посетили 36797 программистов и 7770 роботов. Сейчас ищут 1886 программистов ...

Интерфейсы

Тема в разделе "PHP для новичков", создана пользователем Sarmetr, 26 окт 2022.

Метки:
  1. Sarmetr

    Sarmetr Активный пользователь

    С нами с:
    2 июн 2019
    Сообщения:
    27
    Симпатии:
    0
    Добрый день всем.
    Может мне кто нибудь на "пальцах" объяснить ЗАЧЕМ, именно зачем нужны интерфейсы.
    Сейчас объясню что меня вводит в тупик на примере ниже.

    // это интерфейс
    PHP:
    1. <?php
    2. interface FileInterface{
    3.       public function readFromFile($path);
    4.      public function writeToFile($path, $some);
    5. }?>
    // это реализация кода с помощью интерфейса (к коду не придираться я вывожу смысл)
    PHP:
    1. <?php
    2.   require_once "fileinterface.php";
    3. class Shop implements FileInterface{
    4.      public function readFromFile($path){
    5.          echo "Считываем из файла и возвращаем строку<br />"; // ну или что то другое можно написать
    6.      }
    7.      public function writeToFile($path, $some){
    8.          echo "Записываем в файл данные $some<br />";
    9.      }
    10. }?>
    Вопрос: смысл в такой реализации ??
    Если можно написать БЕЗ интерфейса так

    PHP:
    1. <?php
    2. class Shop {
    3.      public function readFromFile($path){
    4.          echo "Считываем из файла и возвращаем строку<br />"; // ну или что то другое можно написать
    5.      }
    6.      public function writeToFile($path, $some){
    7.          echo "Записываем в файл данные $some<br />";
    8.      }
    9. }?>
    Смысл подключения интерфейса , если код выше все сделает тоже самое , я вот в упор не понимаю.
    Можете мне кто нибудь написать пример(например), где интерфейс действительно нужен и он что то облегчает, решает ?? По мне так , то что я написал БЕЗ интерфейса намного проще, легче и лучше.
     
  2. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Интерфейсы нужны для того, чтоб потом подставлять разные реализации. То есть для полиморфизма. Если его нету, то да, нафиг не сдались.
    Классический пример, который во всех книжках (из реальной практики приводить - это обычно три страницы описывать задачу):

    PHP:
    1. interface Animal {
    2.     public function name(): string;
    3.     public function say(): string;
    4. }
    5.  
    6. class Cat implements Animal {
    7.     public function name(): string { return "кошка";}
    8.     public function say(): string { return 'мяу';}
    9. }
    10.  
    11. class Dog implements Animal {
    12.     public function name(): string { return "собака";}
    13.     public function say(): string { return 'гав';}
    14. }
    15.  
    16. function animalSay(Animal $animal) {
    17.     echo $animal->name(), " говорит ", $animal->say();
    18. }
    19.  
    20. animalSay(new Cat());
    21. animalSay(new Dog());
    Если в двух словах. Если не в двух, читаем https://www.ozon.ru/product/php-8-obekty-shablony-i-metodiki-programmirovaniya-361612458/
    --- Добавлено ---
    Плюс тут в том, что если я заведу сюда корову, лошадь, и вообще весь зоопарк, то функцию animalSay мне менять не нужно будет.
     
    Dimon2x нравится это.
  3. Sarmetr

    Sarmetr Активный пользователь

    С нами с:
    2 июн 2019
    Сообщения:
    27
    Симпатии:
    0
    Все равно не понял

    PHP:
    1. class Cat {
    2.     public function name(): string { return "кошка";}
    3.     public function say(): string { return 'мяу';}
    4. }
    PHP:
    1. class Dog {
    2.     public function name(): string { return "собака";}
    3.     public function say(): string { return 'гав';}
    4. }
    PHP:
    1. function animalSay() {
    2.      Cat::name(), " говорит ", Cat::say();
    3. }
    Вот, то же самое только меньше код и без интерфейса. И даже если добавить всю возможную скотину сюда, с интерфейсом код будет больше, медленнее и непонятнее. Зачем он нужен чисто технически , какие плюсы дает по сравнению с тем что я написал ?? Прочитал кучу инструкций и примеров, никаких плюсов у интерфейсов не нашел и так и не понял зачем они нужны кроме гемороя и усложнения кода. Что с интерфейсом несколько классов (и меньше их не будет, а будет только больше чем без), что без интерфейса.
    В примере выше можно сделать классы для каждого животного (что в общем то и правильно) и пиши в них функции про рога, копыта, кто сказал мяю, а кто гав. Каким боком тут интерфейс помогает ??
     
    #3 Sarmetr, 26 окт 2022
    Последнее редактирование: 26 окт 2022
  4. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Ну если ты только статику понимаешь, пиши вообще без ООП. От классов тогда никакой пользы, они типа просто неймспейсов для функций становятся

    Ещё раз, у меня есть функция animalSay(), которая принимает экземпляр любого класса, вообще любого, который реализует интерфейс Animal. Ей всё равно, передам я ей корову или волка, она будет работать. Твоя функция будет работать только с кошкой, она не универсальная. С моей функцией я могу сделать так:
    PHP:
    1. $animals = [new Cat(), new Dog(), new Cow(), new Tiger() /* и т.д. */];
    2. foreach ($animal as $a) {
    3.     animalSay($a);
    4. }
    С твоей так нельзя.

    Причём в реальной программе массив подобный $animals будет заполняться динамически, а не вот так статически, т.е. всё будет зависеть от пользовательского ввода, а функции animalSay по-прежнему по барабану, кого ты ей передал, главное, чтоб интерфейс реализовывал класс. Плюс контроль за типами от пыхи - если передашь что-то не то, он тебя обложит матом.

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

    Медленнее - не настолько существенно, чтоб учитывать. Непонятнее - если знаешь пыху, и теорию ООП, то всё очевидно. Прочитай Зандстру про паттерны проектирования, я же здесь не буду всю книгу перепечатывать. Больше на 4 строчки кода - ну я как-нибудь переживу :)
    --- Добавлено ---
    Вообще, у всех приёмов ООП есть такой "недостаток", что трудно придумать примеры на 3 строчки, которые были бы сильно осмысленными. ООП для решения сложных задач создавался. Я помню, нам на первом курсе препод на лекции 4 точки на экран с помощью полиморфизма выводил :) Т.е. то, что можно сделать в один оператор Write (мы с паскаля начинали)
     
    artoodetoo нравится это.
  5. Sarmetr

    Sarmetr Активный пользователь

    С нами с:
    2 июн 2019
    Сообщения:
    27
    Симпатии:
    0
    А объясни пожалуйста вот в этом методе
    PHP:
    1. function animalSay(Animal $animal) {
    2.     echo $animal->name(), " говорит ", $animal->say();
    3. }
    он так наследует интерфейс Animal ( Animal $animal ) , ну и принимает переменную ??
     
  6. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Это не метод, а функция (поскольку она не в классе). Она ничего не наследует. Она принимает ссылку на экземпляр класса, который обязан реализовывать интерфейс Animal (в пыхе объекты только по ссылке передаются), после чего, вызывает у него методы name() и say()
     
  7. Sarmetr

    Sarmetr Активный пользователь

    С нами с:
    2 июн 2019
    Сообщения:
    27
    Симпатии:
    0
    Вроде все понятно, но черт голову сломит, классы наследую интерфейсы, последний метод вроде обращается к классам и их методам через интерфейс
    Ну это я понял. В скобках функции пишется (Animal $animal), меня интересует Animal (т.к $animal в твоем случае это либо new Dog либо new Cat), а вот именно Animal что значит, это типо проверка что экземпляр реализует интерфейс Animal , это так пишется ???
     
  8. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Это синтаксис указания типа для аргумента функции, он уже давно в языке имеется.
    --- Добавлено ---
    Если я указываю интерфейс, то будут приниматься экземпляры всех классов, реализующие интерфейс. Если укажу класс, то будут приниматься экземпляры этого класса и его наследников. Сейчас мы ещё можем и скаляры указывать (int, string, bool)
    --- Добавлено ---
    Не к классам, к объектам. Нестатические методы вызываются у объектов. Да, тут доля абстрактного мышления нужна. Киты ООП: абстракция, инкапсуляция, наследование и полиморфизм
    --- Добавлено ---
    Интерфейсы не наследуются, а реализуются. Это своего рода обязательство реализовать те или иные методы.
     
    #8 mkramer, 27 окт 2022
    Последнее редактирование: 27 окт 2022
  9. Sarmetr

    Sarmetr Активный пользователь

    С нами с:
    2 июн 2019
    Сообщения:
    27
    Симпатии:
    0
    Вот, теперь начинает потихоньку быть понятным, что и зачем )) Спс. А все методы в интерфейсе ОБЯЗАТЕЛЬНЫ для исполнения ?? Нельзя например какой то один исполнить, а другой нет ??

    И последний вопрос (возможно), я прсто в методах и функциях часто использовал указание скаляров : int или : string : array и так далее, а если указать тип для аргумента функции как в твоем случае Animal (как пример) , и передать туда другой тип, то будет ошибка ?? Т.е. функция принимает ТОЛЬКО этот тип аргументов, с другими будет ошибка ???
     
  10. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Класс, реализующий интерфейс, обязан реализовать все функции интерфейса, если он не абстрактный. Абстрактный может часть не реализовывать, тогда будут обязаны реализовать его наследники (а экземпляры абстрактного класса создавать нельзя).

    Вызывать можно то, что надо, там где надо, никаких ограничений нету.

    Да, в этом и смысл. Потому что если ты попробуешь у чегой-то ещё вызвать say() или name(), то уже это приведёт к ошибке. А с указанием типа ошибку может заметить ещё IDE до запуска этого кода. Вообще, пыха с каждой версией всё больше типизации добавляет
    --- Добавлено ---
    Так, а если ты про вызов функции, ты получаешь объект, и вызываешь то, что тебе надо. Т.е. если меня не интересует в какой-то конкретной функции название животного, я могу не вызывать name(). Точно так же как и без интерфейса - я же не обязан вызывать постоянно всё, что в класс напихано. Что мне надо, то и вызываю.
    --- Добавлено ---
    Я, в принципе, сам противник популярной нынче практики создавать интерфейсы вообще для всего на свете, я их делаю только там, где я на 100% уверен, что собираюсь использовать полиморфизм. А тестирование предпочитаю сразу интеграционное, как-то послушал об этом доклад, и счёл аргументы весомыми.
     
  11. Sarmetr

    Sarmetr Активный пользователь

    С нами с:
    2 июн 2019
    Сообщения:
    27
    Симпатии:
    0

    Т.е
    PHP:
    1. interface Animal {
    2.     public function name(): string;
    3.     public function say(): string;
    4. }
    5. class Cat implements Animal {
    6.     public function name(): string { return "кошка";}
    7. }
    можно реализовать только name() и ошибки не будет или все таки если наследуешь интерфейс то будь добр реализуй все его функции
    иначе будет ошибка (Класс, реализующий интерфейс, обязан реализовать все функции интерфейса) если я правильно понимаю.??
     
    #11 Sarmetr, 27 окт 2022
    Последнее редактирование: 27 окт 2022
  12. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Реализовать надо всё. Вызывать можно только то, что надо. Просто я это пояснение дал, потому что в прошлом вопросе ты использовал термин "исполнить".

    А реализовать надо всё, если реализовать только name, пыха даст ошибку. Ещё раз. Интерфейсы не наследуются, а реализуются. Наследуются только классы.

    Кстати, поэтому есть буква I в SOLID, Interface Segregation Principle. Т.е. в каждом интерфейсе надо прописывать только те функции, которые будут нужны для конкретной задачи.

    Класс может реализовывать сколько угодно интерфейсов.
     
    Sarmetr нравится это.
  13. Sarmetr

    Sarmetr Активный пользователь

    С нами с:
    2 июн 2019
    Сообщения:
    27
    Симпатии:
    0
    Ок. Спасибо, хоть чуть чуть разъяснил что к чему.
     
  14. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.223
    Адрес:
    там-сям
    лучше не скажешь! поэтому хрен поймешь, пока жизнь тебя не заставит делать что-то большое.

    без ООП код превращается в неуправляемую зловонную кучу, которую хочется с каждым новым заданием хочется убить и переписать с нуля. а при должном понимании ООП код может эволюционировать без попаболи.