Какво е контейнер DI?
Контейнер за изпълнение на зависимости (DIC) е клас, който може да инстанцира и конфигурира обекти.
Това може да ви изненада, но в много случаи не се нуждаете от контейнер за инжектиране на зависимости, за да се възползвате от предимствата на инжектирането на зависимости (накратко DI). В края на краищата дори в предишната глава показахме конкретни примери за DI и не беше необходим контейнер.
Ако обаче трябва да управлявате много различни обекти с много зависимости, контейнер за инжектиране на зависимости би бил наистина полезен. Такъв може да е случаят с уеб приложения, изградени на базата на рамка.
В предишната глава се запознахме с класовете Article
и
UserController
. И двете имат някои зависимости, а именно базата данни и
фабриката ArticleFactory
. И за тези класове сега ще създадем контейнер.
Разбира се, няма смисъл да се използва контейнер за такъв прост пример.
Но ние ще създадем такъв, за да покажем как изглежда и работи.
Ето един прост контейнер с твърд код за горния пример:
Използването му ще изглежда по следния начин
Просто заявяваме обект от контейнера и не е необходимо да знаем как да го създадем или какви са неговите зависимости – контейнерът знае всичко това. Зависимостите се въвеждат автоматично от контейнера. В това е неговата сила.
Досега всичко в контейнера беше кодирано с твърд код. Затова ще направим следващата стъпка и ще добавим параметри, за да направим контейнера наистина полезен:
Внимателните читатели може би са забелязали проблем. Всеки път,
когато получавам обект UserController
, се създава и нова инстанция на
ArticleFactory
и базата данни. Със сигурност не искаме това.
Затова добавяме метод getService()
, който ще връща едни и същи
екземпляри отново и отново:
Първото извикване на например $container->getService('database')
ще създаде
обект от базата данни, който ще съхрани в масива $services
и ще върне
директно при следващото извикване.
Променяме и останалата част от контейнера, за да използва `getService()':
Между другото, терминът „услуга“ се отнася за всеки обект,
управляван от контейнера. Оттук идва и името на метода getService()
.
Имаме напълно функционален контейнер за DI! И можем да го използваме.
Както виждате, не е трудно да се напише DIC. Забележително е, че самите обекти не знаят, че контейнерът ги създава. По този начин можете да създавате всякакви обекти в PHP, без да засягате изходния код.
Ръчното създаване и поддържане на контейнерен клас може бързо да се превърне в кошмар. Затова в следващата глава ще разгледаме контейнера Nette DI, който може да се генерира и актуализира почти автоматично.