За последние 24 часа нас посетили 22963 программиста и 1225 роботов. Сейчас ищут 859 программистов ...

Интерфейсы

Тема в разделе "PHP для профи", создана пользователем askanim, 17 апр 2017.

  1. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Не много облегчил себе жизнь при вызове моделей в контроллере.
    Сделал следующие.
    Создал директорию Моделей.
    Создал директорию Интерфейсов этих моделей.
    И создал Класс модель соединяющий всё это дело в контроллере
    Так покажу собственно саму модель
    PHP:
    1. <?php
    2. /**
    3. * Created by PhpStorm.
    4. * User: Леонид
    5. * Date: 16.04.2017
    6. * Time: 16:24
    7. */
    8.  
    9. namespace Application\Model\Users;
    10.  
    11. use Application\System\Facade\Users\src\UsersInterface;
    12.  
    13. class Users implements UsersInterface
    14. {
    15.  
    16.     private $data_array;
    17.  
    18.     public function getDataArray($data_array) {
    19.         $this->data_array = $data_array;
    20.     }
    21.     public function addUser($data_array) {
    22.         return $data_array;
    23.     }
    24.  
    25. }
    Теперь покажу интерфейс
    PHP:
    1. <?php
    2. /**
    3. * Created by PhpStorm.
    4. * User: Леонид
    5. * Date: 16.04.2017
    6. * Time: 16:22
    7. */
    8.  
    9. namespace Application\System\Facade\Users\src;
    10.  
    11.  
    12. interface UsersInterface
    13. {
    14.     /*
    15.      * ADD User
    16.      *
    17.      * @param $array DATA Array param User
    18.      * */
    19.     public function addUser($array);
    20. }
    Вот как это всё выглядит в контроллере :
    PHP:
    1.  $data_user = ["username"=>"Вася", "useremail"=>"BBKVasya@mail.ru"]; // Какой то массив данных
    2.                 // ADD USER FOR SHEME admin_userc TABLE users
    3.                 $Model = new Model();
    4.                 $Model->settings["Users"] = function (UsersInterface $users) use ($data_user){
    5.                     // Здесь обращаемся к интерфейсу
    6.                     return $users->addUser($data_user);
    7.                 };
    8.                 $user = $Model->getSettings("Users", Users::class); // Получаем ответ от переданной нами функции нами функции чё вернули в ней то и получили
    Теперь покажу Класс модель соединяющий контроллер и модель
    PHP:
    1. <?php
    2. /**
    3. * Created by PhpStorm.
    4. * User: Леонид
    5. * Date: 17.04.2017
    6. * Time: 13:53
    7. */
    8.  
    9. namespace Application\System\Model;
    10.  
    11. use Application\System as Syst;
    12. class Model
    13. {
    14.     public $settings; // callable settings
    15.  
    16.     public function  getSettings ($name, $src) {
    17.         return call_user_func_array($this->settings[$name], Array(new $src()));;
    18.     }
    19.  
    20. }
    В чём суть вопроса, это нормально так делать или же это дизморальщина полная?
    потому что складывается ощущение что я делаю это ради этого.... Но мне кажется это очень удобным использованием, в разработке с применением интерфейсов, для работы с моделями которые работают с БД.
     
  2. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    У тебя есть другая модель User реализующая иную логику? Если нет, то выкинь к чертям интерфейсы до тех пор, пока не появится )
     
  3. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @romach Такая вполне может появиться. Это же работа с базой данных. А вообще я думал Что интерфейсы не только для этого.
    Просто я читал много последние три дня про интерфейсы. И встал вопрос ребром. А он вызывает весь класс Который имплементируется? Или он вызывает только метод который я вызываю? То есть я вроде читал что он весь класс не хранит в оперативки, он хранит только те методы которые описаны в интерфейсе. В теории тогда это должно работать быстрее...
    --- Добавлено ---
    @romach ещё может быть унаследована от этого же интерфейса и ещё чего нибудь....
     
  4. t1grok

    t1grok Новичок

    С нами с:
    29 янв 2017
    Сообщения:
    119
    Симпатии:
    32
    Похоже на вымысел. Любой класс неявным образом объявляет свой интерфейс. Явно объявленный интерфейс всего лишь позволяет устанавливать зависимости на абстрактном уровне, а не на уровне конкретных реализаций.
     
  5. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @t1grok он реализует тот class который ты ему говоришь реализовать по его шаблону(т. есть интерфейсу).
     
  6. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Что-то какая-то мешанина из всего на свете, честно говоря. А что удобного? Твой Model - это что-то типа контейнера DependencyInjection, но на кой это тут?
     
  7. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    На 50% интерфейсы нужны, чтобы instanceof отвечал true вне зависимости от класса и наследования.
    --- Добавлено ---
    И чтобы хинтинг проходить
     
    igordata нравится это.
  8. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    А инверсия зависимостей?
     
  9. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Ну это частный случай использования интерфейсов в PHP. В этом языке существует множество встроенных интерфейсов. И мне кажется, что основной причиной появления интерфейсов в пхп была как раз попытка придать полноценности пользовательским классам, начиная с итераторов.
     
  10. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Это тема создана скорее с целью изучения интерфейсов и понимания их работы и для чего они нужны. Ну... Я как бы в принципе понимаю, но пока не до конца понимаю как их правильно и корректно использовать вот и практиковался.
    --- Добавлено ---
    Я не совсем понял, что это хотя и попытался почитать. инъекция зависимостей (Данных).
    Читал здесь
    Честно в голове только каша после прочтённого.
    А можешь дать пожалуйста пример такого использования, пожалуйста. (только не с доки я там не срастил) Не в плане как делается то что ты написал, а какой нибудь пример для дальнейшей разработки.


    Да и вообще может кто дать примеры использования интерфейсов (Как упрощения жизни при разработке), с дальнейшим использованием самих интерфейсов как обращение к ним. В моём понимании Интерфейс это как полиморфизм классов на данный момент.
    --- Добавлено ---
    С плюшкой множественного наследования других интерфейсов
     
  11. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Идея простая, на самом деле. Вот есть у нас два класса с прямой связью:
    upload_2017-4-18_11-53-44.png
    А теперь мы выделяем из B интерфейс, и ожидаем, что экземпляр класса, реализующего этот интерфейс нам передадут в конструкторе:
    upload_2017-4-18_11-58-12.png
    Надеюсь, в UML ничего не напутал :) StarUML не показывает для интерфейсов методы (я не нашёл, по крайней мере), поэтому нарисовал как абстрактный класс. Что мы в результате получаем? Что мы можем сделать для каких-то целей ещё класс C, тоже реализующий BInterface, подставить его в конструктор A, и A всё равно сможет работать. Тут в принципе вместе получилась и инверсия зависимостей, и внедрение зависимостей. А Dependency Injection Container, насколько я понимаю, позволяет менять зависимости не на уровне одного класса, а на уровне целого приложения
    --- Добавлено ---
    К примеру, при проведении тестов нам не хочется лезть в реальную базу, и мы заменяем хранилище в базе на хранилище в массиве.
    --- Добавлено ---
    P.S. Читал и слышал в одной лекции мнение, что надо сразу всегда писать как на втором рисунке, и никогда не писать, как на первом, но сам так не делаю. Из первого второе получить во время рефакторинга не так уж сложно.
    --- Добавлено ---
    Кстати, о реальном применении. Разработчик фреймворка PHPixie благодаря этому приёму сумел составить полностью независимые компоненты, можно не тащить у него весь фреймворк, а стащить только ORM, к примеру, и пользоваться в программе вообще без фреймоврка или на другом фрейморке.
     
    askanim нравится это.
  12. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    То есть по сути значит я сделал верное решение с использованием интерфейса для модели ?
     
  13. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Ну в верном направлении, хотя приведённый код странный. Ты хранилище пытаешься реализовать, или что?
     
  14. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    @askanim ты не можешь на php почувствовать профит от инъекции зависимостей, потому что подкоркой понимаешь, что интерфейсный метод, который вроде бы есть и вроде бы принимает аргумент правильного типа, может вернуть что-то не то. Получается какая-то двухсторонняя зависимость. User должен иметь метод с нужным названием и этот метод может работать корректно, но у него остается свобода в выборе возвращаемого значения и модель должна под это подстраиваться (как минимум - содержать проверку типа).
    Лучше будет обстоять дело, если ты включишь режим строгой типизации. Ты должен ожидать определенный класс или примитивный тип, но не массив (поскольку не можешь объявить требуемую структуру).

    Вот тебе интерфейсы в другом ракурсе:
    https://php.ru/manual/class.arrayaccess.html
    https://php.ru/manual/class.traversable.html
    https://php.ru/manual/class.countable.html
    и т.д., полный список в мануале, обрати внимание, что каждый из них можно использовать по отдельности или вместе в любой комбинации.
     
    askanim нравится это.
  15. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @mkramer Суть идеи в том, чтобы при построении потом других моделей, я мог иметь возможность воспользоваться уже кодом уже существующими моделями, без дубляжа кода.
    Например есть таблица пользователей и если мне вдруг потребуется обратится к данной таблице чтобы я уже не калякал какой то запрос вообще к этой таблице я просто обращусь уже к готовому методу через интерфейс. Да можно сказать сделать хранилище моделей. Но я пока ещё не полностью додумал алгоритм использования данной логики и как уместить её в mvc вчера хорошую идею дал Игорь, а именно о пропущенной букве в mvc а т.есть не хватает логики исполнения. В моём понимании инструкции поведения внутри контроллера, обращения к моделям. Думаю это можно сделать с целью разделения логики. чтобы контроллер не был особо жирным при проверки данных и плюс не был таким здоровым для обращения к разным моделям.
     
  16. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Ну в моём понимании в букву M входит вся бизнес-логика. Потому что M - это не один класс, это много классов, но которые не занимаются ничем другим, кроме работы с данными (в том числе, и расчётов с этими данными).
     
  17. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @mkramer Не ну с моделью понятно. А логика соединения и вывода в контроллере. А куда делась тогда логика валидации обработки поступающих данных)
     
  18. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    По-разному, зависит от задачи и фреймворка, с которым работаю
     
  19. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Протестил, интерфейсы с хинтингом возвращаемого значения хорошо работают и без включения строго режима, и хорошо стыкуются с интерфейсами без такого хинтинга. То есть если класс имплементирует два интерфейса на один метод, и один из них требует объявить возвращаемый тип, а второй - нет, то в классе нужно объявить, и это будет воспринято как реализация обоих интерфейсов.
    Так что с PHP 7 можно писать полноценную инверсию зависимостей, даже если работаешь со старым кодом и приходится использовать существующие интерфейсы без хинтинга: новые классы и интерфейсы можно писать с ним.
     
    askanim нравится это.