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 контейнер във вашия код.

Това ще ви позволи да разтоварите голяма част от конфигурацията, защото някои от „параметрите“, които извличате от конфигурацията, могат да бъдат предадени като директни зависимости в конструкторите.

И използвайте магическата инстанция Config, където DIC не е чиста опция. Въпреки това вероятно трябва да използвате множество Config екземпляри, всеки от които представлява част от настройките, които се използват заедно.

person tereško    schedule 29.05.2017
comment
Уау, това е наистина добър отговор, @tereško. Но също така съм малко объркан от фразата сетива, която използвахте. Мога ли да ви задам няколко въпроса, за да приведа разбирането си в съответствие с вашия текст? Вие казвате: дори че екземплярът ще използва..., имате предвид: екземплярът на класа, който получава Config обект като зависимост, използва само една или две стойности от Config обект, нали? Също така: казвате Този подход води до скрити зависимости.... прод... - person ; 30.05.2017
comment
Що се отнася до скритите зависимости - наистина не знаех как да го обясня по-добре. От външния клас за обиколка казва, че се нуждае от Config екземпляр, но това, което наистина иска, е да извади стойност от този Config. Това всъщност не е класическа зависимост, но ако се опитате да използвате повторно този код, ще видите същите проблеми, както ако сте използвали анти-модел Регистър. (И да, предполагам, че вашият $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