Dependency Injection
Door Pim -, 16 jaar geleden, 42.266x bekeken
Een tutorial over wat Dependency Injection is, hoe je het gebruikt, wat Dependency Injection Containers zijn en hoe de mijne eruit ziet.
Gesponsorde koppelingen
Inhoudsopgave
- Inleiding
- Dependency Injection
- Dependency Injection Container
- Pcms container in opbouw - 1
- Pcms container in opbouw - 2
- De Pcms container
- Conclusie
Er zijn 39 reacties op 'Classes'
Gesponsorde koppelingen
Goede tutorial! Erg goed en duidelijk uitgelegd, genoeg code voorbeelden en comments. Precies zoals ik van je gewent ben!
Ik kijk wel uit naar een Unit testing tutorial.
Ik heb wel een heel klein typfoutje ontdekt:
Pcms (PIM cms :)) Container in opbouw -1
1e codeblok - regel 15 > \ voor InvalidArgumentException moet weg
Ik kijk wel uit naar een Unit testing tutorial.
Ik heb wel een heel klein typfoutje ontdekt:
Pcms (PIM cms :)) Container in opbouw -1
1e codeblok - regel 15 > \ voor InvalidArgumentException moet weg
Interessante tutorial! Ik heb alleen nog een klein vraagje over het volgende (weet niet zeker of ik het helemaal begrijp):
Als ik het goed begrijp denk ik dat je op regel 20 het volgende wou doen: $c->set('mailer' , func.....}); (aangezien je anders mailer.transport overschrijft)
Verder moet ik zeggen dat het me wel weer mooi aan het denken gezet, kan ik mijn structuur weer een stukje mooier maken :)
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
$c = new Container();
// Stel de parameters in
$c->set('mailer.username', 'foo');
$c->set('mailer.password', 'bar');
$c->set('mailer.class', 'Zend_Mail');
// Stel de transport service in
$c->set('mailer.transport', function($c) {
return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
'auth' => 'login',
'username' => $c->get('mailer.username'),
'password' => $c->get('mailer.password'),
'ssl' => 'ssl',
'port' => 465,
));
});
// Stel de mailer service in
$c->set('mailer.transport', function($c) {
$class = $c->get('mailer.class');
$mailer = new $class();
$mailer->setDefaultTransport($c->get('mailer.transport'));
return $mailer;
});
// De mailer roep je dan zo aan:
$mailer = $c->get('mailer');
?>
$c = new Container();
// Stel de parameters in
$c->set('mailer.username', 'foo');
$c->set('mailer.password', 'bar');
$c->set('mailer.class', 'Zend_Mail');
// Stel de transport service in
$c->set('mailer.transport', function($c) {
return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
'auth' => 'login',
'username' => $c->get('mailer.username'),
'password' => $c->get('mailer.password'),
'ssl' => 'ssl',
'port' => 465,
));
});
// Stel de mailer service in
$c->set('mailer.transport', function($c) {
$class = $c->get('mailer.class');
$mailer = new $class();
$mailer->setDefaultTransport($c->get('mailer.transport'));
return $mailer;
});
// De mailer roep je dan zo aan:
$mailer = $c->get('mailer');
?>
Als ik het goed begrijp denk ik dat je op regel 20 het volgende wou doen: $c->set('mailer' , func.....}); (aangezien je anders mailer.transport overschrijft)
Verder moet ik zeggen dat het me wel weer mooi aan het denken gezet, kan ik mijn structuur weer een stukje mooier maken :)
Method visibility is opgelost.
Een nadeel van get en set is dat je er geen derde parameter mee kan geven (shared). Ik ben er eigenlijk niet zo'n voorstander van... Ook is het vaak onduidelijk in API docs en voor IDEs. Pimple gebruikt ArrayAccess, dat vind ik nog net iets mooier.
Allebei... Wie weet ;)
Een nadeel van get en set is dat je er geen derde parameter mee kan geven (shared). Ik ben er eigenlijk niet zo'n voorstander van... Ook is het vaak onduidelijk in API docs en voor IDEs. Pimple gebruikt ArrayAccess, dat vind ik nog net iets mooier.
Allebei... Wie weet ;)
Nee. Niet helemaal. Er zijn een paar verschillen.
- De service container is 'lazy loading'. De services worden pas bij een verzoek gemaakt.
- De service container is geen losse verzameling objecten, maar een samenhangend geheel waarbij de services dmv dependency injection aan elkaar hanen.
- De service container kan ook configuratie/parameters bevatten, de meeste registries niet.
- De service container is veel cooler :)
- De service container is 'lazy loading'. De services worden pas bij een verzoek gemaakt.
- De service container is geen losse verzameling objecten, maar een samenhangend geheel waarbij de services dmv dependency injection aan elkaar hanen.
- De service container kan ook configuratie/parameters bevatten, de meeste registries niet.
- De service container is veel cooler :)
Pim -:
- De service container is 'lazy loading'. De services worden pas bij een verzoek gemaakt.
Bedoel je hiermee dat een functie pas wordt aangeroepen in Container::get()?
Een registery class stored alleen maar dingen toch, als je er een functie instopt moet je die nog zelf aanroepen na Registery::get()? Of heb ik het nou helemaal mis, ben pas begonnen met design patterns...
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$mailer = new Mailer();
$registry->set('mailer', $mailer);
$container->set('mailer', function () {
return new Mailer();
});
?>
$mailer = new Mailer();
$registry->set('mailer', $mailer);
$container->set('mailer', function () {
return new Mailer();
});
?>
Stel nou dat het heel ingewikkeld is om een Mailer object aan te maken. Bij de registry wordt dat gedaan tijden de configuratie en het zal dus altijd gebeuren, of het nou gebruikt wordt of niet.
Bij de container wordt de mailer pas aangemaakt bij de eerste (in het geval van een gedeelde service) aanroep. Als je het niet gebruikt wordt het mailer object dus ook niet aangemaakt.
Bedenk trouwens dat een service container een vorm van een registry is en een registry een service container kan zijn, als het objecten opbouwt mbv dependency injection.
Nee, niet echt. De service container doet slechts dependency injection voor je. De services zelf krijgen dus netjes hun dependencies binnen en zo hoef je geen lelijke globals te gebruiken en kunnen de services dus ook goed getest worden.
De container zélf kan natuurlijk een singleton zijn, maar dat hoeft absoluut niet en dat raad ik dus niemand aan. Volgens mij is een goede maatstaf dat allen controllers (in een MVC omgeving) over de container beschikken. De rest krijgt zijn dependencies van de container, zonder weet te hebben ervan.
Of begrijp ik niet helemaal wat je bedoelt?
De container zélf kan natuurlijk een singleton zijn, maar dat hoeft absoluut niet en dat raad ik dus niemand aan. Volgens mij is een goede maatstaf dat allen controllers (in een MVC omgeving) over de container beschikken. De rest krijgt zijn dependencies van de container, zonder weet te hebben ervan.
Of begrijp ik niet helemaal wat je bedoelt?
Let wel, dit is alleen een hele simpele variant van een container. Hetgeen wat iets vast houdt en geen dependency injection.
Dependency injection injecteerd de juiste objecten / variabelen in een class zie hier onder
Omdat je alles met interfaces aan elkaar hangt heb je geen harde koppeling en kan je elke class los testen.
Ik raad juist wel mensen aan om een singleton voor container te hebben, sterker nog het zou raar zijn als je twee containers hebt voor je applicatie.
Wat deze tutorial mist zijn:
Dependency resolver,
Class resolver,
Uitgebreidere container: hoe injecteer je bijvoorbeeld extra variabelen of stel je in dat een class als singleton moet gedragen.
Dependency injection injecteerd de juiste objecten / variabelen in een class zie hier onder
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Service1
{
protected $_dataLaag;
public function __construct(IDataLaag $dataLaag)
{
$this->_dataLaag = $dataLaag
}
}
interface IDatalaag
{
}
interface IDatabase
{
}
class DataLaag1 implemenets IDataLaag
{
protected $_database;
public function __construct(IDatabase $database)
{
$this->_database = $database;
}
}
class DataLaag2 implemenets IDataLaag
{
protected $_database;
public function __construct(IDatabase $database)
{
$this->_database = $database;
}
}
class FileDatabase implements IDatabase
{
}
class SqlDatabase implemenets IDatebase
{
}
$container->Bind('IDatabase')->To('SqlDatabase');
$container->Bind('IDatalaag')->To('DataLaag1');
$container->Resolve('IDatalaag'); // datalaag1 + sqldatabase in datalaag1 constructor
$container->Bind('IDatabase')->To('FileDatabase');
$container->Bind('IDatalaag')->To('DataLaag2');
$container->Resolve('IDatalaag'); // datalaag2 + filedatabase in datalaag2 constructor
{
protected $_dataLaag;
public function __construct(IDataLaag $dataLaag)
{
$this->_dataLaag = $dataLaag
}
}
interface IDatalaag
{
}
interface IDatabase
{
}
class DataLaag1 implemenets IDataLaag
{
protected $_database;
public function __construct(IDatabase $database)
{
$this->_database = $database;
}
}
class DataLaag2 implemenets IDataLaag
{
protected $_database;
public function __construct(IDatabase $database)
{
$this->_database = $database;
}
}
class FileDatabase implements IDatabase
{
}
class SqlDatabase implemenets IDatebase
{
}
$container->Bind('IDatabase')->To('SqlDatabase');
$container->Bind('IDatalaag')->To('DataLaag1');
$container->Resolve('IDatalaag'); // datalaag1 + sqldatabase in datalaag1 constructor
$container->Bind('IDatabase')->To('FileDatabase');
$container->Bind('IDatalaag')->To('DataLaag2');
$container->Resolve('IDatalaag'); // datalaag2 + filedatabase in datalaag2 constructor
Omdat je alles met interfaces aan elkaar hangt heb je geen harde koppeling en kan je elke class los testen.
Ik raad juist wel mensen aan om een singleton voor container te hebben, sterker nog het zou raar zijn als je twee containers hebt voor je applicatie.
Wat deze tutorial mist zijn:
Dependency resolver,
Class resolver,
Uitgebreidere container: hoe injecteer je bijvoorbeeld extra variabelen of stel je in dat een class als singleton moet gedragen.
Wat ik met het Singelton gebeuren bedoel is dat Singleton ook een beetje lazy-loading is. Het object wordt pas echt aangemaakt als het nodig is. Verder niets. Zend Framework maakt nog geen gebruik van DI als in Service Containers e.d. maar ZF2 geloof ik wel, weet het niet zeker. Maargoed op dit moment doe ik een freelance opdracht waar ze dingen in SF2 gaan bouwen dus wie weet :)
@daan
'design by contract' kan je toch gewoon met een strong typed argument bij injectie method afdwingen?
En natuurlijk is deze container niet zo uitgebreid als mogelijk is, maar het is wel, net zoals bijvoorbeeld pimple en al helemaal met die configure methode die ik erbij bedacht heb, een volledig functionerende container.
Ook ondersteund de container gedeelde services, zoals ik dat beschreven heb. Waarom zou je dan nog (lelijke en ontestbare) singletons nodig hebben?
Hetzelfde geldt voor een singleton container. Als je dat gebruikt doe je je testbaarheid bij slordig gebruik al snel te niet en waarom zou je het voor jezelf onmogelijk maken twee containers te draaien (voor een test tussen twee chat clients bijvoorbeeld) als dat helemaal niet nodig is?
Als je me wil helpen de container tut uit te breiden tot sf2 dic formaat, heel graag, maar anders snap ik je kritiek niet echt...
'design by contract' kan je toch gewoon met een strong typed argument bij injectie method afdwingen?
En natuurlijk is deze container niet zo uitgebreid als mogelijk is, maar het is wel, net zoals bijvoorbeeld pimple en al helemaal met die configure methode die ik erbij bedacht heb, een volledig functionerende container.
Ook ondersteund de container gedeelde services, zoals ik dat beschreven heb. Waarom zou je dan nog (lelijke en ontestbare) singletons nodig hebben?
Hetzelfde geldt voor een singleton container. Als je dat gebruikt doe je je testbaarheid bij slordig gebruik al snel te niet en waarom zou je het voor jezelf onmogelijk maken twee containers te draaien (voor een test tussen twee chat clients bijvoorbeeld) als dat helemaal niet nodig is?
Als je me wil helpen de container tut uit te breiden tot sf2 dic formaat, heel graag, maar anders snap ik je kritiek niet echt...
@pim,
Wat jij beschrijft is geen dependency injection maar de titel heet wel zo. Als je dat niet snapt weet ik het ook niet meer, je injecteerd namelijk nergens een dependency maar bouwt alleen een simpele container.
Ik werk bijvoorbeeld ook nooit met harde implementaties behalve in mijn domain.
Je houdt bijvoorbeeld bij de container ook niet rekening met dat het geen wat je op vraagt ook weer dependencies heeft. Deze wil je niet, zoals jij doet elke keer zelf injecteren maar gewoon 1 keer instellen.
Sinds wanneer zijn singletons lelijk en onhandig? Een settings object wil je niet twee keer laden, zo zijn er nog vele andere voorbeelden.
Een class als singleton instellen, betekend niet meteen dat deze ontestbaar is. Bij mijn DI container zeg ik gewoon ->AsSingleton(), zo zorg ik er voor dat elke class zich als singleton kan gedragen zolang de DI container maar gebruikt wordt.
In een test gebruik je geen dependency injection dus dat argument gaat niet op maar dat snap je zelf ook wel.
Probeer je te verdiepen in patterns als je daar een tutorial voor schrijft. En kijk ook naar andere talen: java, c#, ruby.
Overigens ben ik geen voorstander van symfony of zend.
Wat jij beschrijft is geen dependency injection maar de titel heet wel zo. Als je dat niet snapt weet ik het ook niet meer, je injecteerd namelijk nergens een dependency maar bouwt alleen een simpele container.
Ik werk bijvoorbeeld ook nooit met harde implementaties behalve in mijn domain.
Je houdt bijvoorbeeld bij de container ook niet rekening met dat het geen wat je op vraagt ook weer dependencies heeft. Deze wil je niet, zoals jij doet elke keer zelf injecteren maar gewoon 1 keer instellen.
Sinds wanneer zijn singletons lelijk en onhandig? Een settings object wil je niet twee keer laden, zo zijn er nog vele andere voorbeelden.
Een class als singleton instellen, betekend niet meteen dat deze ontestbaar is. Bij mijn DI container zeg ik gewoon ->AsSingleton(), zo zorg ik er voor dat elke class zich als singleton kan gedragen zolang de DI container maar gebruikt wordt.
In een test gebruik je geen dependency injection dus dat argument gaat niet op maar dat snap je zelf ook wel.
Probeer je te verdiepen in patterns als je daar een tutorial voor schrijft. En kijk ook naar andere talen: java, c#, ruby.
Overigens ben ik geen voorstander van symfony of zend.
@Daan, ik denk dat jij het niet helemaal snapt? Met testen bedoelen we unit testing. Dan wordt het lastig testen met singletons. Als je dit leest begrijp je wel waarom: http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html
Dat je geen voorstander bent van Zend of Symfony verbaast me wel, je schrijft zelf een framework ofzo? Of je bent fan van een ander framework?
Dat je geen voorstander bent van Zend of Symfony verbaast me wel, je schrijft zelf een framework ofzo? Of je bent fan van een ander framework?
@kees vergis je niet ik snap heel erg goed waar jullie het over hebben.
Het is hoe je de singleton zelf in regelt he, op de manier zoals hun dat doen gaat dat natuurlijk niet werken dat is niet meer dan logisch lijkt me?
Maar als je het instelt op de DI container heb je dit probleem niet, overigens kan je een singleton ook weer injecteren.
Ik vind de frameworks te groot, ik hou liever van iets kleins wat in een paar regels te snappen is als je de bekende patterns kent bijvoorbeeld: MVC, Ioc (Inversion Of Control, waar DI gebruikt wordt), Domain driven design, Repository pattern etc...
Ik maak wel gebruik van delen van het Zend Framework maar dat is meer hun libraries bijvoorbeeld Soap Server WSDL generator is erg sterk.
Het is hoe je de singleton zelf in regelt he, op de manier zoals hun dat doen gaat dat natuurlijk niet werken dat is niet meer dan logisch lijkt me?
Maar als je het instelt op de DI container heb je dit probleem niet, overigens kan je een singleton ook weer injecteren.
Ik vind de frameworks te groot, ik hou liever van iets kleins wat in een paar regels te snappen is als je de bekende patterns kent bijvoorbeeld: MVC, Ioc (Inversion Of Control, waar DI gebruikt wordt), Domain driven design, Repository pattern etc...
Ik maak wel gebruik van delen van het Zend Framework maar dat is meer hun libraries bijvoorbeeld Soap Server WSDL generator is erg sterk.
Dat wordt ook uitgelegd in het artikel Daan, dat het met een DI container wel te testen is.
Dat je frameworks groot vindt is een beetje een raar argument, wat maakt diskspace of grote nou uit? En groot als in zwaar zou ook een loos argument zijn omdat alleen dingen geladen worden die worden gebruikt.
Ik weet niet of je aan grote projecten werkt maar in mijn ogen als je dat zonder een goed framework doet snijd je zelf (al-dan-niet later) in je vingers.
Dat je frameworks groot vindt is een beetje een raar argument, wat maakt diskspace of grote nou uit? En groot als in zwaar zou ook een loos argument zijn omdat alleen dingen geladen worden die worden gebruikt.
Ik weet niet of je aan grote projecten werkt maar in mijn ogen als je dat zonder een goed framework doet snijd je zelf (al-dan-niet later) in je vingers.
Bijzonder, ik werk namelijk ook alleen aan grootschalige projecten en houdt me ook met name bezig met architectuur (speel daarbij ook een consultancy rol) en ik denk dat daar open-source frameworks in meerdere opzichten een essientieel belang vormen voor bedrijven.
Maargoed, ieder zo zijn eigen keuzes ondanks ik me niet in jouw beweging kan vinden.
Maargoed, ieder zo zijn eigen keuzes ondanks ik me niet in jouw beweging kan vinden.
@daan,
Sorry, maar ik snap er niet veel van. Of je nou een framework gebruikt of niet maakt niet zo veel uit, maar wat klopt er nou niet aan mijn tut?
In het eerste hoofdstuk introduceer ik het DI patroon. Dat patroon is simpel: het injecteren van afhankelijkheden ipv ze ter plekke instantiëren. Niet meer, niet minder. Je kan dan met interfaces werken, maar dat is niet de essentie, hooguit een nuttige toevoeging.
Mijn container heeft weinig magie. De injecties doe je gewoon zelf binnen de definitie van de service. Hierdoor moet je meer zelf doen, maar blijft je container zeer simpel, flexibel en kan het elke vorm van di aan. Je schrijft de injectie code immers zelf. De definitie wordt meer 'verbose' (vertaling?), maar hierdoor is het bouwen van de container wel eenvoudig en heel overzichtelijk. Dat was toch precies wat je graag hebt, zo zei je zelf?
En wat er mis is met een static container: je beperkt jezelf. Stel dat je een interactie tussen twee clients wil simuleren en functioneel wil unit testen, bijvoorbeeld in een chat app. Normaliter hebben die elk een eigen request en dus een eigen container. In de test wil je dat dus ook.
Dit lijkt misschien een onwaarschijnlijke situatie, maar het laat wel zien dat statics de testbaarheid kunnen verminderen. En wat is trouwens het verschil tussen een static container en een traditionele global var, waarvan we het allemaal eens zijn dat dat niet mooi is?
En over static services: wat is het verschil met mijn gedeelde services, afgezien van dat de deling niet global is, maar container gebonden, wat zoals ik net zei alleen maar voordelig is?
Je zegt verder dat services geen andere services kunnen aanroepen, maar dat is toch precies wat ik in mijn voorbeeld doe? De mailer.transport service is een dependency die voor meerdere services gebruikt kan worden.
En tot slot: de tutorial, en vooral de eerste twee delen, is gebaseerd op een blogpost van Fabien Potencier, de lead dev van een van de twee grote 'enterprise' frameworks: symfony. Ook is pimple, de container waarop ik de mijne heb gebaseerd, de kern van silex, een niet onbekend micro framework.
Zo erg mis kan ik het dan toch niet hebben?
En als laatste: di wordt niet bij testing gebruikt? Wtf?
Sorry, maar ik snap er niet veel van. Of je nou een framework gebruikt of niet maakt niet zo veel uit, maar wat klopt er nou niet aan mijn tut?
In het eerste hoofdstuk introduceer ik het DI patroon. Dat patroon is simpel: het injecteren van afhankelijkheden ipv ze ter plekke instantiëren. Niet meer, niet minder. Je kan dan met interfaces werken, maar dat is niet de essentie, hooguit een nuttige toevoeging.
Mijn container heeft weinig magie. De injecties doe je gewoon zelf binnen de definitie van de service. Hierdoor moet je meer zelf doen, maar blijft je container zeer simpel, flexibel en kan het elke vorm van di aan. Je schrijft de injectie code immers zelf. De definitie wordt meer 'verbose' (vertaling?), maar hierdoor is het bouwen van de container wel eenvoudig en heel overzichtelijk. Dat was toch precies wat je graag hebt, zo zei je zelf?
En wat er mis is met een static container: je beperkt jezelf. Stel dat je een interactie tussen twee clients wil simuleren en functioneel wil unit testen, bijvoorbeeld in een chat app. Normaliter hebben die elk een eigen request en dus een eigen container. In de test wil je dat dus ook.
Dit lijkt misschien een onwaarschijnlijke situatie, maar het laat wel zien dat statics de testbaarheid kunnen verminderen. En wat is trouwens het verschil tussen een static container en een traditionele global var, waarvan we het allemaal eens zijn dat dat niet mooi is?
En over static services: wat is het verschil met mijn gedeelde services, afgezien van dat de deling niet global is, maar container gebonden, wat zoals ik net zei alleen maar voordelig is?
Je zegt verder dat services geen andere services kunnen aanroepen, maar dat is toch precies wat ik in mijn voorbeeld doe? De mailer.transport service is een dependency die voor meerdere services gebruikt kan worden.
En tot slot: de tutorial, en vooral de eerste twee delen, is gebaseerd op een blogpost van Fabien Potencier, de lead dev van een van de twee grote 'enterprise' frameworks: symfony. Ook is pimple, de container waarop ik de mijne heb gebaseerd, de kern van silex, een niet onbekend micro framework.
Zo erg mis kan ik het dan toch niet hebben?
En als laatste: di wordt niet bij testing gebruikt? Wtf?
@pim, dat je er niet veel van snapt dat zijn we beide eens. Het lijkt me verstandig om gewoon eens wat boeken te lezen over patterns. Voordat je uberhaupt zon tutorial post, een DI container heeft geen magie, die heeft de Resolver al is dat ook geen magie want daar stel je ook zelf op in.
Dat je meer vrijheid hebt slaat natuurlijk nergens op. Op jouw manier ga ik voor elke class alle dependencies injecteren. Das leuk voor 1 class maar niet voor 50, laat staan als er iets veranderd.
Het maakt er ook niet overzichtelijker op dat is een ding wat ik met je eens ben, voor 2 classes is leuk maar niet voor 50.
Hier uit blijkt wel dat je de patterns niet goed onder de knie hebt. Je hebt over Unit testen terwijl je intergratie tests bedoelt. Bij unit tests test je alleen de functionaliteit van 1 class niet interactie tussen twee clients.
Uiteraard kan je mailer service gebruikt worden, maar je opzet is gewoon niet geschikt voor grote applicaties.
Bijvoorbeeld meerlaagse dependency moet je zelf regelen terwijl je dit juist met een DI container uit handen wilt geven.
Anders gebruik je gewoon het factory pattern wat je eigenlijk nu doet, je container is 1 grote factory.
Je zult vast niet helemaal mis hebben, maar essenieele dingen kunnen toch beter. Wat ik ook zei kijk ook naar andere talen, PHP is nou niet echt een object georrienteerde taal.
Ik mag hopen dat je een DI container niet gebruikt bij het unit testen anders sla je de plak echt helemaal mis.
Dat je meer vrijheid hebt slaat natuurlijk nergens op. Op jouw manier ga ik voor elke class alle dependencies injecteren. Das leuk voor 1 class maar niet voor 50, laat staan als er iets veranderd.
Het maakt er ook niet overzichtelijker op dat is een ding wat ik met je eens ben, voor 2 classes is leuk maar niet voor 50.
Hier uit blijkt wel dat je de patterns niet goed onder de knie hebt. Je hebt over Unit testen terwijl je intergratie tests bedoelt. Bij unit tests test je alleen de functionaliteit van 1 class niet interactie tussen twee clients.
Uiteraard kan je mailer service gebruikt worden, maar je opzet is gewoon niet geschikt voor grote applicaties.
Bijvoorbeeld meerlaagse dependency moet je zelf regelen terwijl je dit juist met een DI container uit handen wilt geven.
Anders gebruik je gewoon het factory pattern wat je eigenlijk nu doet, je container is 1 grote factory.
Je zult vast niet helemaal mis hebben, maar essenieele dingen kunnen toch beter. Wat ik ook zei kijk ook naar andere talen, PHP is nou niet echt een object georrienteerde taal.
Ik mag hopen dat je een DI container niet gebruikt bij het unit testen anders sla je de plak echt helemaal mis.
Natuurlijk is het zo dat een container complexer kan, maar waarom zou dat noodzakelijk zijn? Nu is de container klein en overzichtelijk. Onthoud, dit is een tutorial, geen script. Ik probeer hier uit te leggen hoe je de simpelst mogelijke container maakt, niet hoe je een full-featured container maakt. Deze container is echter wel degelijk volledig en daarom in mijn ogen zeer geschikt voor een tutorial.
Jij hebt het voortdurend over een bepaalde implementatie van de container, maar wat is het in essentie anders dan een factory die aan DI doet?
En zoals ik zei, parafraseer ik iemand die weet waar hij het over heeft. Stellen dat hij geen idee heeft waar hij het over heeft, is een beetje zwak zonder een hoop argumentatie.
Jij hebt het voortdurend over een bepaalde implementatie van de container, maar wat is het in essentie anders dan een factory die aan DI doet?
En zoals ik zei, parafraseer ik iemand die weet waar hij het over heeft. Stellen dat hij geen idee heeft waar hij het over heeft, is een beetje zwak zonder een hoop argumentatie.
Om even wat referentie te gebruiken: lees dit eens. In dit artikel wordt de term 'dependency injection' voor het eerst geïntroduceerd en zijn omschrijving komt toch wel sterk overeen met de manier zoals ik het van Fabien Potencier heb 'gejat'.
De container die Fowler beschrijft lijkt inderdaad min of meer op datgeen jij omschrijft, maar is qua functionaliteit hetzelfde als Pimple of bovenstaande container. Slechts de vorm is anders. Deze containers bouwen elk gebruikmakend van DI services op zoals een factory.
De container die Fowler beschrijft lijkt inderdaad min of meer op datgeen jij omschrijft, maar is qua functionaliteit hetzelfde als Pimple of bovenstaande container. Slechts de vorm is anders. Deze containers bouwen elk gebruikmakend van DI services op zoals een factory.
Ik vind het een leuk concept, DI. Doet me sterk denken aan Java`s Service containers. Maar ik mis hier wel de daadwerkelijke DI zelf. Dit is meer een container dan dat er daadwerkelijk DI plaatsvindt. Desalniettemin een erg leuke klasse. Ik zou hem persoonlijk als Singleton gebruiken, dat scheelt heel wat rondgooien van overerven en includen. Althans, laat ik het anders uitleggen, ik zou een abstracte klasse maken, vandaaruit de hoofdcontainer welke een singleton is en een losse container klasse welke vrij te gebruiken is. De hoofdcontainer is dan wel hanteerbaar. Ik zou ook containers als return willen zien, sub containers voor bijvoorbeeld mail. Hierdoor heb je tenminste ook onderscheid in alle dependency`s voor services qua mail etc.
Ik heb wel nog 1 opmerking, de set() methode kijkt niet of er al een key bestaat met x waarde, hierdoor kun je sleutels overschrijven wat misschien niet de bedoeling is? Misschien een exception gooien of een warning genereren dat er al een sleutel als $key bestaat?
Los daarvan vond ik het een erg interessante tutorial, doet me goed dat er eindelijk weer eens goede tutorials te vinden zijn hier :)
ps. is niet om te zeiken, DI wordt namelijk prima uitgelegd, heb het artikel van Fabien ook gelezen en je hebt het prima weten te verwoorden naar bruikbare, goed-te-begrijpen Nederlands.
Ik heb wel nog 1 opmerking, de set() methode kijkt niet of er al een key bestaat met x waarde, hierdoor kun je sleutels overschrijven wat misschien niet de bedoeling is? Misschien een exception gooien of een warning genereren dat er al een sleutel als $key bestaat?
Los daarvan vond ik het een erg interessante tutorial, doet me goed dat er eindelijk weer eens goede tutorials te vinden zijn hier :)
ps. is niet om te zeiken, DI wordt namelijk prima uitgelegd, heb het artikel van Fabien ook gelezen en je hebt het prima weten te verwoorden naar bruikbare, goed-te-begrijpen Nederlands.
Je hebt gelijk in zoverre dat je zelf de DI moet implementeren en dat de container dat niet voor je doet. Daarom is idd service container misschien een betere naam, ookal kan je met de zelf-gespecificeerde factories zeker aan DI doen.
Dat er geen exception wordt gegooid is bewust. Op die manier is het mogelijk core-services aan te passen en dat lijkt me vrij noodzakelijk in een modulaire applicatie.
Maar bedankt voor je feedback, die wordt erg op prijs gesteld :-)
Dat er geen exception wordt gegooid is bewust. Op die manier is het mogelijk core-services aan te passen en dat lijkt me vrij noodzakelijk in een modulaire applicatie.
Maar bedankt voor je feedback, die wordt erg op prijs gesteld :-)
Is dit slechts een vertaling van http://fabien.potencier.org/article/11/what-is-dependency-injection ? Of gaat het verder? Heb de 1e en 2e pagina gelzen... maar heb het idee dat ik niets nieuws ga leren dan.
Sterker nog je leert helemaal niks nieuws en dit is geen dependency injection maar een simpele container en heeft niks met het injecteren van dependencies te maken.
@iVar: zoals Pim (de schrijver van de tutorial) in de inleiding al schrijft...
"De tutorial is gebaseerd op deze van Fabien Potencier...". Je kunt ook even verder lezen dan pagina 1 en 2 dan had je je eigen vraag kunnen beantwoorden.
@Daan: typisch hoe jij er als de kippen bij bent om hier een negatieve reactie te plaatsen, terwijl je voor de rest vrijwel nauwelijks actief bent op het forum. Je laat je wel kennen. Gelukkig zijn er andere mensen die wel iets kunnen leren van deze tutorial en die een wat positievere kijk op het leven hebben.
"De tutorial is gebaseerd op deze van Fabien Potencier...". Je kunt ook even verder lezen dan pagina 1 en 2 dan had je je eigen vraag kunnen beantwoorden.
@Daan: typisch hoe jij er als de kippen bij bent om hier een negatieve reactie te plaatsen, terwijl je voor de rest vrijwel nauwelijks actief bent op het forum. Je laat je wel kennen. Gelukkig zijn er andere mensen die wel iets kunnen leren van deze tutorial en die een wat positievere kijk op het leven hebben.
Interessante reacties. Ik heb het idee dat het mij wordt aangerekend dat ik een tutorial heb geschreven/vertaald waar sommige mensen niets van kunnen leren.
Deze site wordt voornamelijk bevolkt door mensen die beginners zijn en hen hoop ik iets te leren. Vind je deze tekst niet interessant, lees hem dan vooral niet.
Wat betreft het inhoudelijke punt, Daan, ik hoor graag jouw omschrijving van het begrip Dependency Injection. Ik heb het idee dat ik het op pagina 2 redelijk heb omschreven.
En tot slot: ja, dit is een vrije vertaling met een kleine toevoeging. Op dit moment leer ik vooral uit Engelse teksten en ik denk ook dat beheersing van de Engelse taal heel handig is bij het leren programmeren. Dit is echter een Nederlandse site, die mij ooit veel geleerd heeft. Daar wou ik iets voor terugdoen en daarom heb ik deze tekst vertaald/geschreven en dat heb ik duidelijk vermeld. Wat is daar mis mee?
Deze site wordt voornamelijk bevolkt door mensen die beginners zijn en hen hoop ik iets te leren. Vind je deze tekst niet interessant, lees hem dan vooral niet.
Wat betreft het inhoudelijke punt, Daan, ik hoor graag jouw omschrijving van het begrip Dependency Injection. Ik heb het idee dat ik het op pagina 2 redelijk heb omschreven.
En tot slot: ja, dit is een vrije vertaling met een kleine toevoeging. Op dit moment leer ik vooral uit Engelse teksten en ik denk ook dat beheersing van de Engelse taal heel handig is bij het leren programmeren. Dit is echter een Nederlandse site, die mij ooit veel geleerd heeft. Daar wou ik iets voor terugdoen en daarom heb ik deze tekst vertaald/geschreven en dat heb ik duidelijk vermeld. Wat is daar mis mee?
Om te reageren heb je een account nodig en je moet ingelogd zijn.
Inhoudsopgave
- Inleiding
- Dependency Injection
- Dependency Injection Container
- Pcms container in opbouw - 1
- Pcms container in opbouw - 2
- De Pcms container
- Conclusie
PHP hulp
0 seconden vanaf nu