1

Тема: Рефакторинг фабрики

Маю легасі проект, у якому є така конструкція:

class entityCreator
{
    function get($entityName)
    {
        return new $entityName();
    }
}

class entity1
{
    function __contruct()
    {
        global $db;
        ...
    }
}

class entity2
{
    function __contruct()
    {
        global $logger;
        global $memcache;
        ...
    }
}

Таких entity є ~100

Очевидно, що хочу позбутися global
Зараз вже частина системи перебита на symfony.

Найпростіший варіант, мабуть, це визначити всі entity у service і в entityCreator передати serviceContainer
Але не хочеться описувати всі 100 ентіті.

Другий варіант. Враховуючи, що левова частка ентіті використовує тільки базу, у service описати тільки специфічні ентіті. А у функції get перевіряти, якщо у serviceContainer є потрібна ентіті беремо її, якщо ні, тоді return new $entityName($serviceContainer->get('db'));

Мені здається, що це доволі поширена ситуації, можливо хтось порадить, якись кращий варіант?

Подякували: ostap34PHP1

2

Re: Рефакторинг фабрики

Як на мене, тут прямо напрошується dependency injection.
Причому прямо через entityCreator.

Подякували: ailkiv, ostap34PHP2

3

Re: Рефакторинг фабрики

koala написав:

Як на мене, тут прямо напрошується dependency injection.
Причому прямо через entityCreator.

Не зовсім зрозумів(

Пропонуєте реалізувати два DI, один системний serviceContainer, а інший в entityCreator?
І описати всі 100 ентіту?

Виглядає якось надмірно.

Подякували: ostap34PHP1

4

Re: Рефакторинг фабрики

Ні, навпаки: створити якийсь централізований тримач для того, що було global-ами, і передавати його в entity::__construct:

class globalContainer()
{
    function get_db(){...}
    function get_logger(){...}
    ...
}

class entityCreator
{
    function get($entityName, $global_container)
    {
        return new $entityName($global_container);
    }
}

class entity1
{
    function __contruct($global_container)
    {
        $db = $global_container.get_db();
        ...
    }
}
Подякували: ostap34PHP1

5

Re: Рефакторинг фабрики

koala написав:

Ні, навпаки: створити якийсь централізований тримач для того, що було global-ами, і передавати його в entity::__construct:

class globalContainer()
{
    function get_db(){...}
    function get_logger(){...}
    ...
}

class entityCreator
{
    function get($entityName, $global_container)
    {
        return new $entityName($global_container);
    }
}

class entity1
{
    function __contruct($global_container)
    {
        $db = $global_container.get_db();
        ...
    }
}

Але передавати DI в класи це бед практіс.
Тобто передати в entityCreator ще +-.
А у entityN це вже якось зовсім не красиво.

Подякували: ostap34PHP1

6

Re: Рефакторинг фабрики

ailkiv написав:

Але передавати DI в класи це бед практіс.

А не навпаки? https://www.vojtechruzicka.com/field-de … d-harmful/

ailkiv написав:

Тобто передати в entityCreator ще +-.
А у entityN це вже якось зовсім не красиво.

Тоді робіть setter/field injection:

class entityCreator
{
    function get($entityName, $global_container)
    {
        $entity = new $entityName();
        $entity->db = $global_container.get_db();
        return $entity;
    }
}
class entity1
{
    function __contruct($global_container)
    {
        $this->db...
    }
}
Подякували: ostap34PHP1

7

Re: Рефакторинг фабрики

koala написав:
ailkiv написав:

Але передавати DI в класи це бед практіс.

А не навпаки? https://www.vojtechruzicka.com/field-de … d-harmful/

Там контейнер не передають параметром конструктора.

Аргументи чому так не варто робити:
https://medium.com/@cleverti/symfony-de … 45b03fe4ac
https://stackoverflow.com/a/26144509

koala написав:

Тоді робіть setter/field injection:

class entityCreator
{
    function get($entityName, $global_container)
    {
        $entity = new $entityName();
        $entity->db = $global_container.get_db();
        return $entity;
    }
}
class entity1
{
    function __contruct($global_container)
    {
        $this->db...
    }
}

По цьому прикладу виходить, що в entityCreator::get треба зробити switch на entity, що засетити потрібні класи

Подякували: ostap34PHP1

8

Re: Рефакторинг фабрики

А хто сказав, що це має бути саме Symphony container? Пишіть свій власний і збирайте туди що вам треба.
Ну і так, у вас якийсь монстр entityCreator без власної функціональності - він лише дозволяє замість

new entity

писати

entityCreator.get('entity')

Нащо він там узагалі потрібен? Там якась скриптова мова над PHP, чи що? Якщо ні - може, приберете його і передаватимете залежності напряму в конструктори?

Подякували: leofun01, ostap34PHP2

9

Re: Рефакторинг фабрики

Майже) Там гнучкий генератор звітів. І в таких ентіті описуємо, інформацію про параметри.

У чому сенс додаткового контейнера, у ньому ж основні класи (db, logger, products і т.п.) будуть перекидатися з симфоні контейнера?

На даний момент планую так переписати:

class entityCreator
{
    function __construct($serviceContainer)
    {
      $this->serviceContainer = $serviceContainer;
    }

    function get($entityName)
    {
      if ($this->serviceContainer->has($prefixEntity.$entityName)) {
        return $this->serviceContainer->get($prefixEntity.$entityName);
      }

      return new $entityName($this->serviceContainer->get('db'));
    }
}

class entity1
{
    function __contruct($db)
    {
        global $db;
        ...
    }
}

class entity2
{
    function __contruct($db, $logger)
    {
    }
}

+ описую 10-20 ентіту, які потребують специфічних класів, приблизно так
entity.entity2
    class: entity2
    arguments: ['@db', '@logger']
Подякували: ostap34PHP1