The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 11-Фев-23, 12:05  [смотреть все]
Доброго дня Товарищи!

Я тут пишу свои всякие поделки, и вот заинтересовался вопросом, а правильный ли я выбрал подход к созданию экземпляра объекта по его ТИПУ? Поясню это на примере:

Допустим, есть у меня к несколько разных вариаций от общего предка, к примеру виды Документов:


//Общий предок
Class Document {
    const DOC_DOGOVOR = 1;
    const DOC_PISMO = 2;

    static public getDocByType(int $docType){
        switch($docType){
            case self::DOC_DOGOVOR:
                return new Doc_Dogovor();
                break;

            case self::DOC_PISMO:
                return new Doc_Pismo();
                break;
        }

        return false;
    }
}

Class Doc_Dogovor extends Document {
    protected static $docType = Document::DOC_DOGOVOR;
    //Своя какая-то кухня с свойствами и методами такого
    //типа документов ...
}

Class Doc_Pismo extends Document {
    protected static $docType = Document::DOC_PISMO;
    //Своя какая-то кухня с свойствами и методами такого
    //типа документов ...
}

//Получить объект нужного типа (из БД к примеру тип приходит)
$docObj = Document::getDocByType($neededTypeFromDB);


Так вот вопрос собственно в том, насколько оправданно или наоборот плохо и как лучше всего такой тип задачи реализовывать?
А задача значит получение экземпляра объекта указанного типа. Видел, что во всяких автозагрузчиках классов сейчас используется динамическое их получение условно такой схемой что если запрошенного класса нет, он подгружается по имени и дальше также создаётся объект класса, название которого в переменной
$docObj = new $objClassName();

  • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 12:10 , 11-Фев-23 (1) +8 [^]
    Ещё дополню, что почему не стал использовать вариант с получением условно по имени класса в переменной, у меня ощущение, что такое динамическое получение объекта чем то сродни exec(), а такого рода финты вроде не совсем правильно использовать. А варианты типов объектов класса свё равно же создаются и их можно сразу в перечисление switch case добавлять.

    • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 16:07 , 11-Фев-23 (3) +6 [^]
      > Ещё дополню, что почему не стал использовать вариант с получением условно по
      > имени класса в переменной, у меня ощущение, что такое динамическое получение
      > объекта чем то сродни exec(), а такого рода финты вроде не
      > совсем правильно использовать. А варианты типов объектов класса свё равно же
      > создаются и их можно сразу в перечисление switch case добавлять.
      >чем то сродни exec(), а такого рода финты вроде не совсем правильно использовать

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

      • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 20:45 , 11-Фев-23 (8) +5
        > eval и иже с ним плохи в первую очередь из-за того, что
        > в них поступает непроверенный пользовательский код. Если оный в него не
        > поступает, жить можно, вон, один язык на eval опирается как на
        > основной способ расширения синтаксиса и ничего.

        Да, точно спутал я exec с eval'ом. Предубеждение у меня к eval'у. Совсем противоестественно использовать эту конструкцию и никогда её не использую.

    • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 05:00 , 12-Фев-23 (10) +4
      >А варианты типов объектов класса свё равно же создаются и их можно сразу в перечисление switch case добавлять.

      Вот этот вариант подойдёт как решение наполовину (если вы это будете делать не в основном классе, а в подклассах на этапе инициализации класса или опосредованно через базовый класс, но динамически и опять же через инициализацию подкласса, базовый класс не должен знать все подклассы - не в курсе, как там оно именно делается в PHP, но механизм должен быть), но проще было бы динамически получать имя класса - если каких-то дополнительных трудностей нет.

      А вообще, зачем вам получать потомков класса через базовый класс, а не через конструктор собственно потомка?

      • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 08:59 , 12-Фев-23 (12) +6 [^]
        > А вообще, зачем вам получать потомков класса через базовый класс, а не
        > через конструктор собственно потомка?

        Потому что условно в БД хранится тип объекта (к примеру число objType), и мне чтобы через конструктор потомка получать экземпляр объекта - мне надо имя класса этого потомка знать по его objType? И потом делать этот озвученный "динамический трюк" $objItem=new $objClassName();
        А как я узнаю, что в переменной $objClassName - корректное название класса?
        Эта вот неоднозначность меня смущает. Я не могу понять - как получается в случае динамического варианта, что имя класса - экземпляр объекта которого я хочу получить - верное?

        • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 13:56 , 15-Фев-23 (18) +3
          >А как я узнаю, что в переменной $objClassName - корректное название класса?

          А оно надо? Кто пользователь ORM - программист или внешний пользователь, который про эти имена классов вообще знать ничего не должен?

          • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 19:25 , 15-Фев-23 (21) +2
            > А оно надо? Кто пользователь ORM - программист или внешний пользователь, который
            > про эти имена классов вообще знать ничего не должен?

            Пользователь ORM - получается программист, т.е. Я. Она (типа ORM, хотя конечно нет) для построения логики с сущностями которые реализуют объекты в приложении. Но в любом случае неважно должен внешний пользователь знать про имена классов или нет, как для "динамического" варианта я должен соотнести objTypeID из базы с именем класса, чтобы выполнить итоговою строку

            $objItem = new $objClassName();
            ? Варианта вижу 2:
            Или в коде формировать связь objTypeID => objClassName, т.е.
            $objTypeData = [
               Doc_Dogovor::OBJ_TYPE => 'Doc_Dogovor',
               Doc_Pismo::OBJ_TYPE => 'Doc_Pismo',
            ];
            ......
            $objItem = new $objTypeData[$objTypeID]();

            Либо в самой БД хранить не objTypeID - а сразу имя класса, но вроде это совсем грязь, хранить куски кода в БД.

            Или я чего-то не понимаю?

  • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 16:03 , 11-Фев-23 (2) +4
    >[оверквотинг удален]
    > //Получить объект нужного типа (из БД к примеру тип приходит)
    > $docObj = Document::getDocByType($neededTypeFromDB);
    >

    > Так вот вопрос собственно в том, насколько оправданно или наоборот плохо и
    > как лучше всего такой тип задачи реализовывать?
    > А задача значит получение экземпляра объекта указанного типа. Видел, что во всяких
    > автозагрузчиках классов сейчас используется динамическое их получение условно такой схемой
    > что если запрошенного класса нет, он подгружается по имени и дальше
    > также создаётся объект класса, название которого в переменной
    >
    $docObj = new $objClassName();

    Дяденька, а зачем вы диспатчите типы через enum, как будто у вас algebraic data types вместо классов?

  • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 16:13 , 11-Фев-23 (4) +5
    >Так вот вопрос собственно в том, насколько оправданно или наоборот плохо и как лучше всего такой тип задачи реализовывать?

    А это вам как зайдёт, вот вы изобрели в пхп типы данных из хаскеля - осваивайте, укладывая мысль в них.

    • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 20:43 , 11-Фев-23 (6) +4
      > А это вам как зайдёт, вот вы изобрели в пхп типы данных
      > из хаскеля - осваивайте, укладывая мысль в них.

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

      • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 04:50 , 12-Фев-23 (9) +3
        >С хаскелем не знаком кроме как слышал название этого языка.

        Ознакомьтесь на досуге, такая штука есть во всех ML-подобных языках, Haskell, Ocaml, Standard ML и так далее. Заодно расширите кругозор и сможете писать на своём языке так, как раньше не писали, если в функциональном стиле не пишете (но тут было бы проще ознакомиться с Scheme, я учил ФП с него, правда вот алгебраических типов в нём нет).

        Вы изобрели, грубо говоря, вот это:
        data Point = Point2D Double Double | Point3D Double Double Double

        В хаскеле это объявление записи по имени Point, у которой есть два варианта: Point2D из двух координат типа Double и Point3D из трёх координат. Тип Point закрытый - его нельзя расширить, при этом вся работа с данными в основном заворачивается на тип Point, а не на подтипы. В языках же с классами и их наследованием класс, как правило, открытый - на основе одного класса вы можете сделать очень много потомков и подпотомков, при этом основные методы родительского класса должны работать при этом без особых изменений. И вот своим case по тегам подтипов в родительском классе вы нарушаете наследование без проволочек, превращая тип в закрытый, как в хаскеле. Разумеется, после этого вам и придётся со временем всё больше работать со своим типом так, как будто он нерасширяемый.

    • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 20:44 , 11-Фев-23 (7) +5
      > А это вам как зайдёт, вот вы изобрели в пхп типы данных
      > из хаскеля - осваивайте, укладывая мысль в них.

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

  • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 07:01 , 12-Фев-23 (11) +5
    сделай обычный class Document. От него наследуются class Dogovor и class Pismo (еще обзови их class DoroBop и class nuCbMo, раз так фанатеешь от русских названий - сарказм на всякий случай). Класс Document при этом не должен знать о существовании своих подклассов и никак их не упоминать. Далее создай в совершенно отдельном месте функцию, которая принимает $typeFromDb и делает по нему return new КонкретныйКласс, можно через switch.
    • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 09:04 , 12-Фев-23 (13) +6 [^]
      > сделай обычный class Document. От него наследуются class Dogovor и class Pismo
      > (еще обзови их class DoroBop и class nuCbMo, раз так фанатеешь
      > от русских названий - сарказм на всякий случай). Класс Document при
      > этом не должен знать о существовании своих подклассов и никак их
      > не упоминать. Далее создай в совершенно отдельном месте функцию, которая принимает
      > $typeFromDb и делает по нему return new КонкретныйКласс, можно через switch.

      Если что, на самом деле эти Документы, Договора и Письма - чистая выдумка для иллюстрации. С моей текущей задачей конкретно такие сущности никак не связаны.

      По поводу организации функцией, а не в родительском классе - в чём у такого подхода принципиальная выгода или "правильность"?

      • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 15:11 , 12-Фев-23 (14) +5
        > По поводу организации функцией, а не в родительском классе - в чём
        > у такого подхода принципиальная выгода или "правильность"?

        Класс Document не должен знать о существовании своих подклассов, т. к. это открытый класс. Я могу написать по месту ад-хок class Issue1488_Document extends Document специально для юнит-теста, и мне не придется вводить фуфловый $docType = 1488, которого в базе естессно не будет. Функция -- это пример для простейших систем без подгрузки кода по требованию. Я могу представить себе систему, в которой class LetterDocument подгружается только тогда, когда он реально нужен. В этой системе модуль "поддержки писем" зарегистрировал бы docType под номером 420 и указал бы, что "если встретишь docType = 420, то загрузи такой-то класс из такого-то файла, а я гарантирую, что это будет подкласс от Document". Похожим образом делает линукс с драйверами: встретив PCI-устройство, линукс смотрит в свой modalias на предмет того, нет ли модуля, предоставляющего драйвер для PCI-устройства с таким-то идентификатором, и если есть - загружает его.

      • Какой верный путь для получения экземпляро объектов по их типу?, !*! ACCA, 03:54 , 13-Фев-23 (16) +3
        Коллеги, я в растерянности. Такое впечатление, что вы вернулись к бредовым идеям самомодифицирующегося кода.

        А ничё, что вас там ждёт cyclomatic complexity?

  • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 18:55 , 12-Фев-23 (15) +8 [^]
    Фабричный метод с маппингом - подход имеющий право на жизнь. Вопрос в том, для чего это применять.

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

    • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 19:57 , 15-Фев-23 (24) +3
      > Фабричный метод с маппингом - подход имеющий право на жизнь. Вопрос в
      > том, для чего это применять.
      > Очевидно, что у вас есть некая универсальная форма, которая посылает ид типа
      > создаваемого документа. И дальше вы создаете документ исходя из его ид.
      > И в базу потом пишете с тем же самым ид.
      > Вместо этого можно для каждого типа документа сделать свои формы, тип создаваемого
      > документа разруливать по маршруту обработчика, ид для базы держать в константе
      > класса и работать с ним только при записи в базу -
      > то есть, в контроллере вообще никогда.

      Не хотел в нудные подробности углубляться, но если это поможет пониманию и оконкретит что главное как лучше это реализовать, то вот, опишу более полно и близко к оригиналу:

      Есть такая сущность, как Статья. Это сущность из которой будет формироваться условно страница с самой этой Статьёй:


      //Отображение её в БД
      TABLE Article (
          id     SERIAL PRIMARY KEY,
          title  CHAR(20) NOT NULL
      )

      Статья состоит из кусков разных типов объектов - Частей Статьи.

      //Отображение Частей Статьи в БД
      TABLE ArticleParts (
          id     SERIAL PRIMARY KEY,
      artID     BIGINT UNSIGNED NOT NULL,
      partType   TINYINT UNSIGNED NOT NULL,
      partOrder  TINYINT UNSIGNED NOT NULL,
          FK(artID) => Article(id)
      )

      Так вот поле partType - это как раз тот самый objTypeID по которому мы понимаем Часть Статьи какого типа это:

      //Общий предок Частей Статьи
      Class ArticlePart {
          const PART_TEXT;        //Чисто текстовый блок
          const PART_IMG_GALLERY; //Набор картинок в блоке
          const PAT_POLL;         //Блок с голосованием
          .......

          //Получить объект нужного типа
          static public & getPartObjByType($objType){
              $objItem = false;

              switch($objType){
                   case ...:
                       $objItem = ....;
                       break;
                   .... ......
              }
          }
      }

      //Классы самих Частей Статьи
      Class ArticlePart_TEXT extends ArticlePart {
          static const OBJ_TYPE = ArticlePart::PART_TEXT;

          //У каждого вида Части Статьи свой способ оформления в БД,
          //со своими таблицами и связями и пр.
          public function DB_Save(){
              .....
          }

          //Тут к примеру у каждого вида Части Статьи своя генерация HTML под него
          public function getHTML(){
              .....
          }
      }

      И условно статью предполагается создавать из таких вот блоков разных типов. Они могут быть интерактивными, каждый из блоков, со своей связанной с пользователем информацией и пр.
      А уже как у статьи в общем может быть там пагинация и прочая херня. Короче велосипед, но мой и хочу чтобы колёса сразу квадратными не выбирались :)

      • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 13:26 , 16-Фев-23 (25)
        Вроде понятно. У вас контроллер компонует результаты дочерних контроллерчиков. Можно имена классов просто в базу сохранять, без искусственных partType. Выборок по этим ид нет же?
        • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 21:17 , 16-Фев-23 (26) +1
          > Вроде понятно. У вас контроллер компонует результаты дочерних контроллерчиков. Можно имена
          > классов просто в базу сохранять, без искусственных partType. Выборок по этим
          > ид нет же?

          Блин... Ну вот сама принципиально идея сохранять имена классов в БД...
          Ну т.е. условно есть скептическое отношение к языку basic, оператору goto, к использованию непроверенного пользовательского ввода во всякого рода SQL-инъекциях, к использованию конструкции eval, не является ли использование данных из БД в качестве исполняемого кода - плохой практикой?
          Ведь если в БД хранится имя класса, то мы должны использовать что-то типа:

          $objItem = $stringFromDB();
          . Т.е. как я вижу это - есть концепция "динамического кода", когда сам код программы - неясен на момент исполнения, и во время него более того тоже меняется.
          Т.к. в процессе исполнения получается сам код программы становится результатом его работы.
          А есть условно "статический код", т.е. в ближайшем приближении - код который можно скомпилировать в исполняемый файл и запустить сам по себе. Всякие eval() и $objFromString() вроде бы представляют собой часть динамической составляющей.

          Вот я и хочу разобраться, насколько это имеет смысл. Я так понял, что среди плюсов динамического подхода: Проще реализация - исключаем часть "конечного автомата по выбору класса для Объекта"

          Минусы у динамики - Смешение кода и данных, т.к. код для создания объекта берётся в любом случае из внешнего источника (БД или Роутинг из URL), также я думаю к минусам можно отнести скорость исполнения (если динамически инклудить файлы с описанием класса для Объекта)

          Плюсы и минусы у Статики - соответственно противоположные.

          Так ли это? Какие ещё есть варианты реализации таких вот как Товарищ выше описал "Контроллеров" и их "Контроллерчиков"?

          • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 13:42 , 17-Фев-23 (27) +1
            > Блин... Ну вот сама принципиально идея сохранять имена классов в БД...

            Вы можете туда интерфейс сохранять, а не конкретный класс. И через DI контейнер получать конкретную реализацию. Это вот именно то, что вы хотите в плане поведения, на самом деле.
            Айдишки искусственны, удобства от них имеют косвенный характер. Будь у вас документо-ориентированная БД и вам бы в голову не пришло их использовать.

            Хранить в базе код и эвалом исполнять - это фактически serverless концепция, вроде AWS Lambda. Так тоже можно! Любые извращения возможны. Если вам доставляет разбираться в этих концепциях, писать свои реализации - это одна история. Если нужно сделать, чтобы работало (и забыть) - другая. Я подозреваю, что необходимости что-то делать с кодом у вас вообще нет.

            • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 21:15 , 17-Фев-23 (28) +1
              > Вы можете туда интерфейс сохранять, а не конкретный класс. И через DI
              > контейнер получать конкретную реализацию. Это вот именно то, что вы хотите
              > в плане поведения, на самом деле.

              Пожалуйста объясните, что такое DI контейнер? Просто пример в несколько строчек для иллюстрации. Я абсолютно не понимаю, о чём речь.

              > Я подозреваю, что необходимости что-то делать с кодом у вас вообще нет.

              Ну как... Поддерживать его, развивать логику и функционал на основе этой "фабрики объектов". Это, если я правильно понял суть реплики, не просто код для изучения концепции с теоретической целью. Цель вполне себе ясная, а этот вопрос встал на этапе реализации некоторых сущностей.


              • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 14:59 , 20-Фев-23 (29)
                > Пожалуйста объясните, что такое DI контейнер? Просто пример в несколько строчек для
                > иллюстрации. Я абсолютно не понимаю, о чём речь.

                На пальцах - это штука, которая знает, как инстанцировать объект указанного вами класса, чтобы вы могли не заниматься этим в своем коде. Дергаете ее либо вручную, либо она автомагически создает для вас объекты в аргументы методов ваших классов.
                https://laravel.com/docs/10.x/container
                https://symfony.com/doc/current/components/dependency_inject...

                > Ну как... Поддерживать его, развивать логику и функционал на основе этой "фабрики
                > объектов". Это, если я правильно понял суть реплики, не просто код
                > для изучения концепции с теоретической целью. Цель вполне себе ясная, а
                > этот вопрос встал на этапе реализации некоторых сущностей.

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

  • Какой верный путь для получения экземпляро объектов по их типу?, !*! Аноним, 14:01 , 15-Фев-23 (20) +6 [^]
    Надо не играть в бабу Вангу и чётко спросить:

    >Я тут пишу свои всякие поделки

    В чём смысол поделки, самопальная ORM?

    • Какой верный путь для получения экземпляро объектов по их типу?, !*! Вервер, 19:30 , 15-Фев-23 (23) +6 [^]
      > Надо не играть в бабу Вангу и чётко спросить:
      >>Я тут пишу свои всякие поделки
      > В чём смысол поделки, самопальная ORM?

      Нет, смысл самой поделки не ORM, смысл того что я спрашиваю - некое подобие ORM, но оно не самоцель, а лишь часть в моей общей замути. Спрашиваю, чтобы на этапе пока не накодил много объектов выбранным (и опробованным) способом который в вопросе и описал, и не пришлось потом всё перелопачивать из-за того, что выбранный способ унылый.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру