PHP MVC: класс конфигурации как зависимость или только с константами класса, доступными извне?

В моем проекте MVC (PHP 7.1) у меня есть класс Config и множество файлов конфигурации, каждый из которых выглядит так:

return [
    'web' => [
        'host' => 'localhost',
        //...
    ],
];

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

class AbstractView {

    private $config;

    public function __construct(Config $config) {
        $this->config = $config;
    }

    private function prepareContext() {
        $this->assign('appHost', $this->getConfig()->get('web/host'));
    }

}

Поскольку передать объект Config в моем приложении довольно сложно, я подумал о реализации класса Config только с константами класса, например:

class Config {

    const WEB_PROTOCOL = 'http';
    const WEB_HOST = 'localhost';

}

и получить к ним доступ напрямую с помощью

class AbstractView {

    private function prepareContext() {
        $this->assign('appHost', Config::WEB_HOST);
    }

}

Мои вопросы:

  1. Действительно ли это хорошая альтернатива, учитывая, что я хочу полностью избежать статических состояний в своем приложении?
  2. Является ли эта альтернатива «статичной» или совсем нет?
  3. А как насчет тестируемости (у меня пока нет опыта)?

Большое спасибо.


person Community    schedule 29.05.2017    source источник


Ответы (1)


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

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

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

Рекомендация

Начните использовать DI Container в своем коде.

Это позволит вам разгрузить большую часть конфигурации, потому что некоторые "параметры", которые вы извлекаете из конфигурации, могут быть переданы как прямые зависимости в конструкторах.

И используйте волшебный экземпляр Config, где DIC не является чистым вариантом. Тем не менее, вам, вероятно, следует использовать несколько экземпляров Config, каждый из которых представляет часть настроек, которые используются вместе.

person tereško    schedule 29.05.2017
comment
Вау, это действительно хороший ответ, @tereško. Но меня также немного смущают смыслы фраз, которые вы использовали. Могу я задать вам несколько вопросов, чтобы привести мое понимание в соответствие с вашим текстом? Вы говорите: даже думал, что экземпляр будет использовать.... Вы имеете в виду: экземпляр класса, который получает объект Config в качестве зависимости, использует только одно или два значения из Config объект, да? Также: вы говорите Этот подход приводит к скрытым зависимостям.... Прод... - person ; 30.05.2017
comment
Что касается скрытых зависимостей - я действительно не знал, как это лучше объяснить. Извне класс тура говорит, что ему нужен экземпляр Config, но на самом деле он хочет извлечь значение из этого Config. На самом деле это не классическая зависимость, но если вы попытаетесь повторно использовать этот код, вы увидите те же проблемы, что и при использовании анти-шаблона Registry. (И да, я предполагаю, что ваш $this->getConfig()->get('something') возвращает null, если значение не установлено.) - person tereško; 30.05.2017
comment
[ Я удалил этот текст, потому что вы уже ответили на него :-) ] В противном случае я должен вам сказать: ваша рекомендация по сегрегации и внедрению зависимостей с использованием DIC, которая у меня уже есть, например, все еще Auryn, - это идея, о которой я действительно не думал. о. Я нахожу это очень естественным и лучшим методом. - person ; 30.05.2017
comment
Да, мной тоже поздно. Но вы знаете, как это бывает: Я не могу спать, не зная всего о конфигах :-) tereško, ты помнишь свой ответ на мой вопрос дней 5 назад? PHP MVC Несколько баз данных, несколько преобразователей данных?. Я следовал вашему принципу и очень этому рад: теперь я могу без проблем жонглировать несколькими подключениями, мапперами, адаптерами, репозиториями. Я еще раз благодарю вас! :-) Доброй ночи - person ; 30.05.2017