• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Dependency Injection - IoC - inne parametry konstruktora

Object Storage Arubacloud
0 głosów
462 wizyt
pytanie zadane 13 września 2016 w PHP przez deimos Nowicjusz (120 p.)

Problem jest następujący. Mam klasę do której wstrzykuje zależności za pomocą konstruktora. W jednej zależnych klas jednym z parametrów konstruktora jest zmienna typu string np. $modulelId, która jest potrzebna do stworzenia obiektu, którego będę używał wewnątrz innej klasy. Rejestrację zależności oraz tworzenie instancji wymaganych obiektów chciałem odseparować do innej warstwy, w której wykorzystuję kontener DI. W chwili użycia obiektu, do którego inicjalizacji potrzebna jest zmienna $moduleId, np brana z pętli for wewnątrz innej klasy, nie mogę tego zrobić za pomocą DI kontenera. Musi to zostać wywołane wewnątrz klasy, która posiada zmienne $moduleId. Czy w takim przypadku można olać DI i użyć po prostu new czy lepiej wywalić z konstruktora parametr $moduleId i zrobić setter, który będzie używany przez klasę posiadającą zmienne $moduleId? Wtedy tworzeniem wszystkich instancji mógłby się zająć kontener DI. Z drugiej jednak strony taki stan utworzonego obiektu bez ustawionej zmiennej $moduleId jest sytuacją niepożądaną i tak naprawdę obiekt od początku jego inicjalizacji powinien mieć ten atrybut ustawiony.

Jak prawidłowo powinienem zaprojektować strukturę klas, tak aby było to zgodne z IoC?

Przykład:

<?php

class ModuleManager
{
	private $modulePropertyGetter;
	private $moduleSearcher;
	
	// pierwszy sposób
	public function __construct(ModuleSearcherInterface $moduleSearcher)
	{
		$this->moduleSearcher = $moduleSearcher;
	}
	
	// drugi sposób z zależnością w konstruktorze
	public function __construct(ModulePropertyGetterInterface $modulePropertyGetter, ModuleSearcherInterface $moduleSearcher)
	{
		$this->modulePropertyGetter = $modulePropertyGetter;
		$this->moduleSearcher = $moduleSearcher;
	}
	
	public function getModulesNames()
	{
		$modules = $this->moduleSearcher>getModules();
		$modulesNames = [];
		foreach ($modules as $moduleId) {
			// pierwszy sposób
			$modulePropertyGetter = new ModulePropertyGetter($moduleId);
			$modulesNames[] = $modulePropertyGetter->getName();
			
			// lub
			// drugi sposób
			$this->modulePropertyGetter->setModule($moduleId);
			$modulesNames[] = $this->modulePropertyGetter->getName();
		}
	}
}

class ModulePropertyGetter implements ModulePropertyGetterInterface
{
	private $moduleId;
	private $someClass;
	
	// pierwszy sposób z konstruktorem
	public function __construct($moduleId, SomeClassInterface $someClass)
	{
		$this->moduleId = $moduleId;
		$this->someClass = $someClass;
	}
	
	// drugi sposób przez setter
	public function setModule($moduleId)
	{
		$this->moduleId = $moduleId;
	}
	
	public function getName();
	{
		/** do something */
		return $name;
	}
	
	/**
	Inne metody używające $this->moduleId;
	*/
}

// Wykonanie z DI
$contaniner = new DIContainer();
$conteiner->registerDependencies(/** dependencies */);
$moduleManager = $container->get('ModuleManager');

 

2 odpowiedzi

+1 głos
odpowiedź 13 września 2016 przez efiku Szeryf (75,160 p.)
Możesz wzorować się na tym:: https://github.com/symfony/dependency-injection
Lub po prostu użyć tego komponentu w swojej aplikacji (niż wymyślać koło na nowo)

:)
Dokumentacja: https://symfony.com/doc/current/components/dependency_injection.html

Zanim ktoś mi powie, że znowu wciskam symfony, to powiem tak:

-> Jest to prawdopodobnie komponent który spełnia oczekiwania.
-> To tylko komponent nie całe SF.
-> Polecam co sprawdzone i dobre
-> Robię w SF.
komentarz 13 września 2016 przez Comandeer Guru (601,450 p.)
Oprócz tego z SF jest jeszcze np http://container.thephpleague.com/
komentarz 13 września 2016 przez efiku Szeryf (75,160 p.)
no no :)

i tamten komentarz :D
komentarz 13 września 2016 przez deimos Nowicjusz (120 p.)
Nie chodziło mi o samo zastosowanie czy implementację komponentu kontenera. Akurat ja pracuje na frameworku Yii2 i tam korzystam z gotowego kontenera DI http://www.yiiframework.com/doc-2.0/guide-concept-di-container.html który jak najbardziej spełnia moje wymagania.

Chodziło mi o samą konstrukcję klas i ich zależności. W podanym przez mnie przykładzie logika wstrzykniętej klasy (obiektu) wymaga użycia parametru konstruktora, który nie jest znany w warstwie kontenera DI, co skutkuje tym, że obiekt jest tworzony nie przez kontener i nie w wyniku odwróconej zależności (co łamie zasadę IoC) tylko w implementacji innej klasy za pomocą operatora new (co podobno w obecnych czasach wzorców i SOLIDów jest uznawane za nieładne).

Rozwiązuje to w ten sposób, że usuwam tą zależność z konstruktora i dokładam setter, który ustawia ten parametr przez klasę która go zna. I wtedy tworzenie instancji obiektów (również tych wynikających z zależności) zostawiam kontenerowi w swojej warstwie.
Pytanie czy taki zabieg stworzenia settera tylko po to, żeby obiekt mógł się utworzyć za pomocą kontenera a nie operatora new wewnątrz innej klasy jest warty zachodu. Poza tym i tak trzeba pamiętać o ustawieniu tego parametru bo bez niego obiekt staje się bezużyteczny (dlatego naturalnym wydaje się wsadzić go do konstruktora, ale wtedy nie mogę go utworzyć prze kontener DI).
0 głosów
odpowiedź 14 września 2016 przez maly Nałogowiec (37,190 p.)
Albo ModulePropertyGetter jest bez sensu albo nie rozumiem jego przeznaczenia, przecież objekty na których będzie operował będą musiały mieć publiczny interfejs a skoro tak to jaki sens ma chowanie go za kolejnym publicznym interfejsem.
komentarz 16 września 2016 przez deimos Nowicjusz (120 p.)
Chodzi o to, że obiekty ModulePropertGetter są tworzone na potrzeby obiektu ModuleManager (wewnątrz niego), bo on posiada niezbędne parametry do ich utworzenia. W takim układzie nie mogę przerzucić tworzenia tych obiektów na kontener DI, bo tam nie są znane wymagane parametry. Zastanawiam się czy takie rozwiązanie będzie zgodne z IoC i czy nie powinienem jednak wszystkich zależności co do tworzenia obiektów przerzucić na kontener DI.

Podobne pytania

0 głosów
1 odpowiedź 455 wizyt
pytanie zadane 17 lutego 2021 w Algorytmy przez CSSoup Mądrala (6,460 p.)
0 głosów
1 odpowiedź 276 wizyt
pytanie zadane 24 czerwca 2017 w PHP przez Marduczek Użytkownik (520 p.)
0 głosów
1 odpowiedź 404 wizyt

92,576 zapytań

141,425 odpowiedzi

319,650 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...