Objecten doorgeven, zo min mogelijk afhankelijk

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Write Down

Write Down

05/02/2013 22:57:17
Quote Anchor link
Hi,

Ik zit me af te vragen hoe ik op een transparante manier object het best kan doorgeven. Echter wil ik er voor zorgen dat de klassen niet afhankelijk van mekaar worden. Ik denk dat ik daar momenteel vrij goed in slaag. Alleen, ik ben er nog niet geheel uit. Ik zoek dus meningen, en eventuele alternatieven.

Ik ben bezig met het ontwikkelen van een klein simpel framework. Het framework is opgebouwd volgens het MVC principe. Alle requests komen binnen op mijn 'FrontController'. Deze bepaalt dan welke end controller er gebruikt moet worden, welke actie er uit gevoerd moet worden, paramaters...

Om de resources netjes te gebruiken, heb ik in mijn FrontController gebruik gemaakt van een Service Container. Deze houdt o.a. de log-service bij en de database-service. Deze worden dan overgedragen naar de uiteindelijke controllers, dus volgens mij zit dat goed qua afhankelijkheden en resources.

Verder heb ik ook gebruik gemaakt van interfaces. Bijvoorbeeld, de klasse database verwacht een parameter (via de constructor) ConfigInterface, zodanig dat ik vrij ben wat soort config object ik nu eigenlijk meegeef. Zolang het maar de ConfigInterface implementeert. Hierdoor creëer ik volgens mij voldoende flexibiliteit.

Ik vraag me af of dit dus een nette manier is.
 
PHP hulp

PHP hulp

28/01/2020 09:15:45
 
Wouter J

Wouter J

05/02/2013 22:59:40
Quote Anchor link
ja, dat is het. :) (veel meer valt hier niet op te reageren naar mijn mening)
 
Write Down

Write Down

05/02/2013 23:05:01
Quote Anchor link
Ok, mooi.

En ik vermoed dan dat de volgende opzet ook degelijk is:

Ik heb een abstract klasse, die alle controllers (behalve de front controller) uitbreiden. In deze abstracte controller, heb ik ook weer een service container. Deze houdt momenteel een service bij om formulieren te verwerken en om template-functies uit te voeren.
 
Wouter J

Wouter J

05/02/2013 23:05:59
Quote Anchor link
Nee, als het goed is heeft je hele applicatie toegang tot 1 en dezelfde service container waar dus alle services van de hele applicatie instaan. Dit geeft je de mogelijkheid het framework te kunnen aanpassen in de applicatie code.
 
Write Down

Write Down

05/02/2013 23:13:50
Quote Anchor link
Is het dan bv een goed idee om de service container, die dus in de front controller wordt gemaakt, door te geven? Met doorgeven bedoel ik dan, dat de abstracte controller deze krijgt. In de abstracte controller kan ik dan alsnog extra services aan de container toevoegen.
 
Wouter J

Wouter J

05/02/2013 23:45:52
Quote Anchor link
Nee, services moet je op 1 plek toevoegen en dat is bij het opzetten van je applicatie. Dan stel je doormiddel van configuratie bestanden of ServiceProvider klassen in welke services er allemaal zijn, dit moet niet 'run time' gebeuren.

Met het eerste deel van je reactie (doorgeven van container) ben ik het wel eens. Totdat je van je controller services gaat maken, sommige devs houden daarvan, dan mag je alleen weer de services injecteren die je in de controller nodig hebt. Je moet je namelijk aan de regel houden: Als een klasse een service is mag het alleen andere services krijgen, niet de hele container. In elk ander geval moet de klasse juist de hele container (of niks) krijgen.
 
Write Down

Write Down

06/02/2013 00:06:30
Quote Anchor link
Ok, bedankt :-)
 
Jasper DS

Jasper DS

06/02/2013 09:36:46
Quote Anchor link
Dus alle mogelijke services zitten op voorhand in een config bestand? Tijdens het lopen van de applicatie kunnen er geen services worden toegevoegd? Dat lijkt met niet echt flexibel?
 
Wouter J

Wouter J

06/02/2013 09:38:48
Quote Anchor link
Het hoeft ook helemaal niet flexibel te zijn. Als je services 'on run time' aanmaakt weet je nooit of je nu nou wel of niet toegang hebt tot die service, door alles in 1 keer te registeren, voordat de rest van de code wordt uitgevoerd, zorg je dat je altijd toegang hebt tot alle mogelijk services.

Waarom zou je je services willen aanpassen 'on run time'?
 
Jasper DS

Jasper DS

06/02/2013 09:42:56
Quote Anchor link
Oke dus voor je je app runt moet je alle mogelijk servises van alle mogelijke scenarios in een xml bestand of een ander config bestand hebben staan?
 
Wouter J

Wouter J

06/02/2013 09:43:56
Quote Anchor link
Ja, of je gebruikt ServiceProviders klasses die de services instellen. Of je gebruikt ze allebei :)
 
Jasper DS

Jasper DS

06/02/2013 09:58:30
Quote Anchor link
Kortom gewoon een plek waar de services gedefineerd zijn. In een config bestand bijvoorbeeld zo:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
database
    class = \PDO
    host = localhost
    usernaam = root
    ww = wachtwoord
    database = db1
storage
    class = Framework\Blabla\PDOStorage
    db = database
...


horen alle mapper hier ook in? dus:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
userMapper
    class = Namespace\Mapper\...\UserMapper
    storage = storage


En waar hoort dit bestand? In de app map of in de framework map?
Gewijzigd op 06/02/2013 10:56:01 door Jasper DS
 
Write Down

Write Down

06/02/2013 11:36:10
Quote Anchor link
Hmmz inderdaad, ik vraag me ook af hoe dat dan zit. Momenteel heb ik in mijn front controller iets staan als:

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
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
<?php
        try {

            $this->container = new ServiceContainer();
            $this->container->set('logger.class', 'DebugLog');
            //$this->container->set('logger.file', $_SERVER['DOCUMENT_ROOT'] . '/error_log');
            $this->container->set('logger', function($c) {
                        $class = $c->get('logger.class');
                        //return new $class($c->get('logger.file'));
                        return new $class();
                    },
true);

            $this->logger = $this->container->get('logger');
            $this->logger->error('<h1>Debuglogger</h1>');
        }
catch (Exception $e) {
            echo 'fatal error';
        }

        try {
            $this->container->set('configparser.class', 'JsonParser');
            $this->container->set('configparser.file', $this->getAbsolutePath() . '/config.json');
            $this->container->set('configparser', function($c) {
                        $class = $c->get('configparser.class');
                        return new $class($c->get('configparser.file'));
                    });
//not needed to share

            $this->container->set('config.class', 'Config');
            $this->container->set('config', function($c) {
                        $class = $c->get('config.class');
                        return new $class($c->get('configparser'));
                    });


            $this->container->set('database.class', 'Database');
            $this->container->set('database.config', $this->container->get('config'));
            $this->container->set('database.logger', $this->container->get('logger'));
            $this->container->set('database', function($c) {
                        $class = $c->get('database.class');
                        return new $class($c->get('database.config'));
                    },
true);

            $this->container->set('form.class', 'Form');
            $this->container->set('form', function($c) {
                        $class = $c->get('form.class');
                        return new $class();
                    },
true);

            $this->container->set('template.class', 'Template');
            $this->container->set('template.layout', 'default');
            $this->container->set('template', function($c) {
                        $class = $c->get('template.class');
                        return new $class($c->get('template.layout'), $c->get('form'));
                    });

            $this->parseUri();
        }
catch (Exception $e) {
            $this->logger->critical($e->getMessage());
        }

?>
Gewijzigd op 06/02/2013 11:36:27 door Write Down
 
Jasper DS

Jasper DS

06/02/2013 11:42:40
Quote Anchor link
Staat dat zo in je front-controller? Ik dacht dat je dat allemaal in een appart bestand moest instellen. Je moet de configuratie en de verwerking splitsen. Dat is wat ik toch heb afgeleid van dit topic.
 
Write Down

Write Down

06/02/2013 11:51:58
Quote Anchor link
Dit stukje code staat inderdaad in een ander bestand :-). Maat technisch gezien, staat het dus wel in mijn front controller. Dat je het opsplitst in meerdere bestanden, is naar mijn mening eerder voor de duidelijkheid. Doe je dat niet, dan is dat ook geen ramp, alleen minder netjes.
 
Jasper DS

Jasper DS

06/02/2013 14:21:31
Quote Anchor link
Oke daar ben ik het met eens. Ik ga mijn config waarschijnlijk uit een .yml lezen (ben er nog mee aan het experimenteren) misschien is dat ook een optie?
 
Write Down

Write Down

06/02/2013 14:33:55
Quote Anchor link
Dat is een keuze dat je maakt natuurlijk. Zelf ga ik voor Json. Leesbaar & compact formaat. Verder wil ik ook delen van mijn applicatie uitwisselbaar maken, en dan is Json ook welkom. Verder een koud kunstje om van json naar XML te gaan :-)
 
Wouter J

Wouter J

06/02/2013 15:40:42
Quote Anchor link
Oké, wat je kunt doen is gebruik maken van een config bestandje. Hiervoor deel je het op in 2 config bestandjes: 1 voor de Applicatie (in bijv. config/services.yml) en 1 voor het Framework (ergens in de framework map).

Hoe ik zo'n configuratie bestand eruit zou laten zien en hoe je dat moet parsen heb ik zojuist in andere topics verteld: http://www.phphulp.nl/php/forum/topic/dependency-injection/89060/#639305 (vanaf deze reactie en verder)

Wat je ook kan doen is ServiceProviders maken. Een voorbeeldje daarvan kun je zien in Silex of in een applicatie van mij: Inspector. Hier zie je dat de providers worden aangeroepen, hoe deze providers eruit zien kun je hier bekijken.
 
Write Down

Write Down

08/02/2013 19:09:12
Quote Anchor link
Het enige punt dat ik dan nog zie, je geeft aan je provider een config mee. Je config, die wordt geparsed door een 'config parser', en daarna gebruik je een 'config class'. Eigenlijk dus ook een service. Deze heb je dan wel dubbel, tenzij je deze eerst aan je service container toevoegd. Al zie ik daar het nut niet van in, aangezien je deze specifieke config niet meer op een andere plaats gaat gebruiken.

Of zie ik dat helemaal verkeerd?
 



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.