[oop] services... in de knoop

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 volgende »

Ozzie PHP

Ozzie PHP

29/08/2014 00:50:17
Quote Anchor link
Ola,

Op advies van enkelen van jullie leek het me een goed idee om van iedere service een apart object te maken wat je vervolgens toevoegt aan een container. Dus we hebben zeg maar een service met wat instellingen en die voegen we toe aan een container.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$container
->add(new Service($instellingen, 'foo'));
$container->add(new Service($instellingen, 'bar'));
?>

Als ik dan een service nodig heb, doe ik:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$foo
= $container->get('foo');
?>

Omdat ik met losse Service objecten werk, weten die niet van elkaars bestaan af. En daar komt mijn "probleem". Stel nu dat de service 'foo' gebruik maakt van de service 'bar', hoe krijg ik dat dan voor elkaar?

Het lijkt mij dan dat het service object 'foo' toegang moet hebben tot de container waar het object in zit. Houdt dit dan in dat ik op het moment dat ik een service object toevoeg aan de container, ik de container als parameter moet meegeven aan het service object, dus zoiets:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$container
->add(new Service($instellingen, 'foo', $container));
?>

Of is er een betere oplossing waardoor de service objecten gebruik kunnen maken van elkaar?
 
PHP hulp

PHP hulp

29/03/2024 10:03:35
 
Ward van der Put
Moderator

Ward van der Put

29/08/2014 08:18:24
Quote Anchor link
Ozzie PHP op 29/08/2014 00:50:17:
Als ik dan een service nodig heb, doe ik:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$foo
= $container->get('foo');
?>

Aha, als ik een $container->get() zie, vermoed ik dat er een $container->set() in de buurt is. Dáár haalt je 'foo' dus de 'bar' vandaan.

Symfony kent bijvoorbeeld vergelijkbare parameter accessors:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$container
->setParameter('mailer.transport', 'sendmail');
$container->getParameter('mailer.transport');
$container->hasParameter('mailer.transport');
?>
 
Wouter J

Wouter J

29/08/2014 09:52:32
Quote Anchor link
En om te bepalen welke service waar geinjecteerd moer worden gebruik je een reference object oid met daarin het id van de service die geinjecteerd moet worden:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
$mailer
= new Service('Ozzie\Mail\Mailer');
$container->set('ozzie.mailer', $mailer);

$newsletter = new Service('Ozzie\Newsletter\SendManager', array(
    new
Reference('ozzie.mailer'),
));

$container->set('ozzie.newsletter.manager', $newsletter);
?>
 
Ozzie PHP

Ozzie PHP

29/08/2014 12:58:47
Quote Anchor link
@Ward

Wat ik wil bewerkstelligen is dat een service object alle informatie bevat om de service aan te maken. Dus het service object bevat de properties "class" en "parameters". Dat complete object voeg ik dan toe (add) aan de container. Op het moment dat ik een service opvraag, wordt er een instance (object) van de class aangemaakt op basis van de parameters. Bij de parameters wil ik aangeven of er een andere service moet worden gebruikt, bijv. door een $-teken voor die parameter te zetten. Dus bijv. parameters: foo = 10, bar = $bar. Het $-teken bij $bar geeft dan aan dat het om een andere service gaat. Het service object ziet nu dus dat er een $bar service moet worden gebruikt als parameter, maar het service object zelf beschikt niet over de container waar $bar in zit. Dat is het probleem.

@Wouter

Hoe haalt jouw new Reference dan 'ozzie.mailer' op? Dat Reference object moet dan toch ook toegang hebben tot de container?

Ik zie trouwens in jouw voorbeeld dat je de ID 'ozzie.mailer' toch meegeeft aan de container en niet aan het object zelf. Waarom toch die keuze? Of was dit gewoon een voorbeeldje?
 
Wouter J

Wouter J

29/08/2014 13:51:20
Quote Anchor link
Een definitie is alleen de definitie, niks meer. Het mag dus geen acties uitvoeren. Dat doet de container (of een service processor die door de container wordt gebruikt).

Waarom ik IDs gebruik is omdat symfony dat simpelweg doet, maar ook om de reden die ik in je andere topic heb geschreven
 
Ozzie PHP

Ozzie PHP

29/08/2014 13:55:03
Quote Anchor link
>> Een definitie is alleen de definitie, niks meer.

Ik snap 'm even niet. Zit in zo'n service object dan alleen een definitie? Ik dacht namelijk dat het service object ook de class instance aanmaakt. Dat was toch de bedoeling van die afzonderlijke objecten? Of begrijp ik het verkeerd?
 
Ozzie PHP

Ozzie PHP

30/08/2014 16:04:42
Quote Anchor link
* BUMP *

Wat hoort er dan in zo'n los service object te zitten? Alleen de definitie gegevens? Of bouwt het service object ook de instance op... of doet juist de container dat en is het service object dus niet meer dan een data object (en kan ik het wellicht beter definition object noemen ipv service object)?

Graag jullie hulp. Alvast dank.
 
Ward van der Put
Moderator

Ward van der Put

30/08/2014 16:09:29
Quote Anchor link
Het is een keuze, maar ik zou persoonlijk liever complete services dan alleen servicedefinities in zo'n container laden.
 
Ozzie PHP

Ozzie PHP

30/08/2014 16:14:10
Quote Anchor link
Ward, dat dacht ik dus ook. Echter Wouter schrijft:

"Een definitie is alleen de definitie, niks meer. Het mag dus geen acties uitvoeren. Dat doet de container (of een service processor die door de container wordt gebruikt)."

Ik snap niet hoe ik het nu moet oplossen eerlijk gezegd. Het probleem is dat wanneer service A service B nodig heeft, ze elkaar (via de container) moeten kunnen aanspreken. Als je complete service objecten gebruikt, dan gaat dat niet want die hebben geen toegang tot de container.

Ik vind het een beetje lastig uitleggen. Snap je wat ik bedoel te zeggen?
 
Ward van der Put
Moderator

Ward van der Put

30/08/2014 16:22:22
Quote Anchor link
Het kan beide, daarom is het een keuze :-)

Er is hier geen goed of fout. Het hangt ervan af wat je met die services wilt doen.

- Het ene uiterste is: ik zet de services alvast voor je klaar, zodat ze op afroep beschikbaar zijn.

- Het andere uiterste is: mocht je een service nodig hebben, dan kun je die hier vinden.
 
Ozzie PHP

Ozzie PHP

30/08/2014 16:41:09
Quote Anchor link
Ward, daar gaat het eigenlijk niet om. De service wordt ALTIJD pas aangemaakt als je 'm (voor de 1e keer) aanroept. Ik denk dat je niet helemaal snapt wat ik bedoel.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$foo
= new Service(['class' => 'Foo', 'params' => ['foo' => true, 'bar' => '$bar']]);
// Bij de parameters zie je '$bar' staan. Het $ teken geeft aan dat het om een andere service gaat.
$container->add($foo, 'foo_service');
?>

Op het moment dat ik de foo service aanroep, moet er dus een instance worden aangemaakt. Voor het aanmaken van die instance heb ik de bar service nodig. Om die bar service te kunnen gebruiken, moet je die kunnen aanroepen vanuit de container. Stel nu dat ik de instance aanmaak vanuit het foo service object, dan heb ik geen toegang tot de container. Tenzij ik op het moment dat ik de foo service aanmaak, ik de container als 3e parameter meegeef. Dan krijg je dit, maar dat lijkt me niet echt de bedoeling:

$foo = new Service(['class' => 'Foo', 'params' => ['foo' => true, 'bar' => '$bar']], $container);

Het alternatief is dan dat je de instance vanuit de container zelf aanmaakt, maar dan is een service object dus niets meer dan een data object waarin je een paar properties opslaat.

Wat is nu precies de bedoeling van zo'n service object en wat is wijsheid?
Gewijzigd op 30/08/2014 16:42:42 door Ozzie PHP
 
Ward van der Put
Moderator

Ward van der Put

30/08/2014 16:48:23
Quote Anchor link
Ja, ik begrijp wel wat je wilt doen, maar...

- je kunt iets dat uit twee stappen bestaat soms beter uit twee lagen opbouwen en

- je hebt soms een singleton nodig terwijl je hebt gelezen dat je dit nooit mag gebruiken ;-)

>> Op het moment dat ik de foo service aanroep, moet er dus een instance worden aangemaakt.

Precies, tenzij je al een foo had en de logica gebiedt dat er maar één foo mag zijn.
 
Ozzie PHP

Ozzie PHP

30/08/2014 16:53:53
Quote Anchor link
Maar de voor mij belangrijkste vraag is op dit moment wat die losse service objecten (die je toevoegt aan de container) behoren te doen. Maken die losse objecten daadwerkelijk zelf de service/instance aan, of bevatten ze alleen de definitie en maakt de container de service/instance aan?
 
Ward van der Put
Moderator

Ward van der Put

30/08/2014 17:03:14
Quote Anchor link
Beide, maar daarom zou ik het ook splitsen en er twee lagen van maken. Eventueel zelfs drie of vier als je bijvoorbeeld een cache gebruikt.

Vereenvoudigd:

- Je hebt bedrijfskritieke services die je áltijd nodig hebt. Die kun je alvast instantiëren.

- Je hebt services die je niet altijd nodig hebt maar die wel kritiek zijn. Daarvan wil je op afroep een instantie hebben.

- Je hebt services die moeten kunnen worden hergebruikt. Die horen in een cache.

- Je hebt services die niet kritiek zijn maar "gewoon handig". Die horen op een extra laag die de andere services niet in gevaar brengt.
 
Ozzie PHP

Ozzie PHP

30/08/2014 17:17:58
Quote Anchor link
Ward, thanks... maar nog niet het antwoord op mijn vraag. De vraag is heel simpel. Ik ga het nog een keertje uitleggen.

Stel we hebben een Ward service met als class => Ward en als parameters name => Ward en status => Put.

Deze gegevens stoppen we in een apart object(X). Dit object stoppen we vervolgens weer in een container(Y), zodat ik de Ward service kan ophalen uit de container op het moment dat ik daar behoefte aan heb. Dus op het moment dat ik de Ward service nodig heb, spreek ik de container aan en krijg ik een Ward object terug: $ward = $container->get('Ward');

Mijn enige vraag is nu... wie gaat (op basis van de class-naam en de parameters) het Ward object aanmaken? Maakt het losse object(X) dit aan, of maakt het container object(Y) dit aan?
 
Wouter J

Wouter J

30/08/2014 17:21:54
Quote Anchor link
>> Maakt het losse object(X) dit aan, of maakt het container object(Y) dit aan?

Dat mag je zelf bepalen. 't is jouw code, er zijn geen regels, er is geen OO wetboek. Je probeert opnieuw te zoeken naar regels en je wordt opnieuw duizelig omdat je ontdekt dat 2 mensen het op 2 verschillende manieren aanpakken. Ik kan je vertellen, haal er een 3de persoon bij en je hebt 3 plannen van aanpak.
 
Ozzie PHP

Ozzie PHP

30/08/2014 17:24:36
Quote Anchor link
Wouter, thanks. Hoe zou jij het zelf dan doen? Maakt bij jou de container of het losse object de instance aan? En stel dat het losse object de instance zou aanmaken, hoe krijgt het losse object dan toegang tot de container? Heb je daar een idee over?
 
Wouter J

Wouter J

30/08/2014 17:39:53
Quote Anchor link
Ik zou een ServiceProcessor class maken die doormiddel van de ServiceDefinition en de Container een service aanmaakt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class Container
{
    // ...
    public function get($id)
    {

        if (isset($this->instances[$id])) {
            return $this->instances[$id];
        }
elseif (isset($this->services[$id])) {
            $service = $this->serviceProcessor->process($this->services[$id], $container);

            if ($this->services[$id]->isShared()) {
                $this->instances = $service;
            }


            return $service;
        }
else {
             throw new UnknownServiceException::serviceNotAvailable();
        }
    }
}

?>
 
Ozzie PHP

Ozzie PHP

30/08/2014 19:21:11
Quote Anchor link
Ah, thanks Wouter! En die serviceProcessor geef je die dan mee als parameter aan de constructor van de container?
 
Wouter J

Wouter J

30/08/2014 19:23:28
Quote Anchor link
Ik zou iets als dit hanteren:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php

class Container
{
    protected $serviceProcessor;

    public function __constuct(ServiceProcessor $processor = null)
    {

        $this->serviceProcessor = $processor ?: new ServiceDefinitionProcessor();
    }
}

?>

Op deze manier kun je een custom service processor gebruiken, maar default je tot een processor voor service definitions.
 
Ozzie PHP

Ozzie PHP

30/08/2014 19:28:30
Quote Anchor link
Ah oké... ik snap 'm. Thanks :)
 

Pagina: 1 2 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.