Object georiënteerd denken

Door PHP erik, 13 jaar geleden, 18.587x bekeken

geupdate! OOP begint bij je denkwijze. Het heeft weinig met de techniek zelf te maken. Hier probeer ik je te laten beseffen hoe OOP werkt, in plaats van het je aan te leren.

Gesponsorde koppelingen

Inhoudsopgave

  1. Besef wat objecten zijn
  2. Objecten herkennen
  3. Foute denkwijze
  4. Inheritance
  5. Praktijk (geupdate)

 

Er zijn 37 reacties op 'Object georinteerd denken'

PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Ik zal nog een keer terugkomen op deze tutorial en dan een volledig praktische tutorial met praktische voorbeelden geven. Deze tutorial is meer geschreven voor mensen die al klooien met classes en dergelijke maar nog niet goed begrijpen hoe ze bepaalde keuzes maken.
Terence Hersbach
Terence Hersbach
13 jaar geleden
 
0 +1 -0 -1
mooi tut.. zeer begrijpelijk. ik dacht dat je even de mist in ging met je oog :)
Peter Wessels
Peter Wessels
13 jaar geleden
 
0 +1 -0 -1
Dankje PHPerik, ik begrijp het nu echt weer iets meer. Die praktijk tutorial lijkt mij ook heel leerzaam dus daar wacht ik ook nog even op.

Dankje;)
Manaus
Manaus
13 jaar geleden
 
0 +1 -0 -1
mijn complimenten, een zeer duidelijke en intressante tutorial!!
Jeffrey H
Jeffrey H
13 jaar geleden
 
0 +1 -0 -1
Ik vind dit niet echt OOP:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$validator
->setValidator('name', new Validator_Not_Empty());
new
Validator_Not_Empty() //<<<<<< ??????
?>

Doe het dan zo(Met constants, en geef NOT_EMPTY dan een Bitmask number, dus een vermenigvuldigd getal 2 zoals 16, 32,64,128 etc.):
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$validator->setValidator('name', $validator->NOT_EMPTY);

Je laat een functie geen class naam returnen, en daarvoor zijn classen ook in het begin uitgevonden: Het vergiftigd je NameSpace niet zo verschikkelijk, het helpt je vooral ook geordend werken.

Voor de rest, wel goede voorbeelden gegeven.
Jelmer -
Jelmer -
13 jaar geleden
 
0 +1 -0 -1
Je maakt van een validator juist wel een object, omdat het dan niet uit maakt wat voor object het is, zolang het maar voldoet aan de eisen (de interface) van een validator. Die validator kan gemaakt zijn door John Doe, Evil Mark, Ethean, maakt niet uit.

Zou je een variabele of constante gebruiken zoals jij aandraagt, dan moet er dus een algemene klasse wezen die al deze validators bevat. Wat nu als dat een klasse is die je niet wilt, kan, moet, mag, durft aan te passen? Daarnaast zou dat ding veel te complex worden. Wat nu als je een hele specifieke voorwaarde hebt, eentje die alleen in deze ene applicatie nodig is. Is die dan de moeite waard om in de klasse die gedeeld is in ieder project te stoppen?

edit: Houd je objecten simpel. Bedenk niet 1 object dat al het werk doet, nee, heb liever voor iedere taak 1 mannetje object dat gespecialiseerd is in zijn taak en in niets anders dan zijn taak. Vervolgens is er wel een overkoepelend manager object dat de specifiekere objecten dirigeert, en niets anders doet dan dirigeert. Want dat is zijn specifieke taak.
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Zeer goed!!

Kreeg opeens een goed idee om mijn filter class iets aan te passen aan het voorbeeld (zie http://www.phpfreakz.nl/library.php?sid=26740)
Winston Smith
Winston Smith
13 jaar geleden
 
0 +1 -0 -1
Goede tutorial! Het is erg verhelderend om nog eens in alledaagse taal te lezen waar het nu om draait. Zo op het scherm ziet het er echter altijd logisch en simpel uit, maar in de praktijk merk ik dat ik toch nog loop te worstelen altijd.
Bij het maken van bv. een simpele kalender/agenda kan je Dag, Maand en Jaar ook als objecten zien (wellicht extend Dag ook een Maand, en Maand een Jaar (of is een dag een eigenschap van een maand? :P)?), maar ik vraag me dan af of het wel nut heeft om zo 'diep' te gaan. Waarom niet een Datum-object of iets dergelijks, met als parameter de datum? Dan wordt het mij toch weer te abstract... :)
Peter Wessels
Peter Wessels
13 jaar geleden
 
0 +1 -0 -1
Maar PHPErik, ik zie wel uit naar je praktijk tutorial! Of als iemand een soortgelijke tutorial weet laat het me weten!
Orhan
Orhan
13 jaar geleden
 
0 +1 -0 -1
@Kasper, op jouw vragen zou ik ook graag antwoord willen hebben. Kan je dat niet naar phperik sturen?
Winston Smith
Winston Smith
13 jaar geleden
 
0 +1 -0 -1
Och, PHPerik of een andere OOP-guru (*kuch* Jelmer *kuch*) leest dit vast wel morgen of overmorgen, en dan gaat hij die vragen allemaal beantwoorden en daar gaan we hem heel erg dankbaar voor zijn: Orhan->doneert('bier'); :P

Edit:
Naamgeving vind ik overigens nog zoiets. Heel werkwoord gebruiken (doneren; vind ik persoonlijk mooier), of een vervoeging (doneert, leest 'natuurlijker' en makkelijker). Of toch in het Engels? Send? Transmit? Submit? Transport? Dat zijn ook dingen die ik door elkaar zou halen.

En....in Orhan->doneert('bier'); is 'bier' natuurlijk een object, dus dan zou je ook kunnen typecasten (ervan uitgaande dat Orhan alleen biertjes geeft aan mensen): Orhan->doneert(Bier Heineken);. Toch? :P
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
// waarom bier niet goed is voor je server:
$bier = new Bier();

while(!empty($bier->glas())) {
    $bier->drink();
    if(empty($bier->glas())) {
        $bier = new Bier();
    }
}

?>

Edit:
Er zat een insect in mn bier gla.. class
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
ONDERSTAAND IS ALLEMAAL IN DE TUTORIAL TOEGEVOEGD. BEDANKT KASPER EN ANDEREN VOOR DE GOEDE VRAGEN!

@Tha Wizekid
Quote:
Doe het dan zo(Met constants, en geef NOT_EMPTY dan een Bitmask number, dus een vermenigvuldigd getal 2 zoals 16, 32,64,128 etc.):
Zo gooi je juist je flexibiliteit weg. Als je een Validatie-object meegeeft, een adapter zoals dat zo mooi heet, dan kun je de werking binnen die adapters defini?ren. Als jij 20 validators hebt en je werkt met constants zoals jij, dan krijg je dus weer ??n grote spagetticlass.

Quote:
Je laat een functie geen class naam returnen
Dat gebeurt ook absoluut niet. Ik geef een nieuw object mee, die vervolgens wordt gebruikt om te valideren. Dit is juist veruit de meest effici?nte en logische oplossing.

In jouw geval zou het trouwens altijd nog Validator::NOT_EMPTY worden. Maar goed, niet gebruiken, dan gooi je al je flexibiliteit weg en strandt het schip weer in grote bergen met spagetti.

@Kasper
Naamgevingen
Wat betreft naamgevingen, bekijk bijvoorbeeld de Zend standaard eens. Het is naar mijn mening het meest logisch om bij de namen van methods te denken aan wat het doet. Gebiedende wijs dus. Stuur! Maak! Lig! Update! etc. Verder is Engels meestal gewoon een internationale standaard, maar ook een beetje eigen smaak.

Dag, Maand, Jaar, Datum?
Het is logisch dat je voor een datum een apart object maakt, omdat een datum een vrij specifiek 'iets' is. Nu kun je bedenken: heeft een dag, maand of jaar zelf nog specifieke eigenschappen? Op zich wel, want een dag valt binnen de range(1,31), etc. Maar het zijn wel constante waardes waar verder niet veel spannends mee gebeurt. In dit geval raad ik aan gewoon het Datum-object eens te maken en dan te kijken of je code flexibeler wordt van aparte dag/maand/jaar-objecten of dat het juist een rotzooitje wordt.

Je moet gewoon kijken of het nut heeft een laag dieper te gaan, of het nut heeft om nog meer objecten te maken voor sub-onderdelen. Als je in je datum-object allemaal variabelen moet gaan setten die specifiek voor een dag gelden, of voor een maand, dan ben je dus te veel binnen ??n object bezig.

Dit soort dingen is gewoon een beetje logisch nadenken en kijken of je niet meerdere objecten aan het defini?ren bent binnen ??n object. Als je meerdere functies krijgt als formatDay(), forwardDay($days), resetDay(), etc, dan zal je wel een apart object moeten gebruiken. Want dan zijn de methods niet meer het Date-object aan het manipuleren, maar het (niet-bestaande & te cre?ren) Day-object.

@Kasper 'Dag extends Maand'
Een dag kan nooooit een maand extenden. Zie de PHPerikregel in deze tutorial. Je kunt jezelf vragen: "Is een dag ook een maand?" -> nee!. Dus je kan 'm absoluut niet extenden. Stel dat je een class Maand maakt dan bevat die class (mogelijk) wel een array met allemaal Dag-objecten. Want een maand bevat w?l meerdere dagen.

Nutteloos voorbeeldje:

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

class Month
{
    const $monthdays = array(1 => 31, 2 => 30); // date() kan ook

    protected $days = array();

    public function __construct($month)
    {

           $this->makeDays( $this->monthdays[$month] );
    }


    protected function makeDays($amount)
    {

           for ($i = 1; $i <= $amount; $i++) {
                $day = new Day($i);
                $this->days[$i] = $day;
           }
    }
}


?>


In de praktijk zou ik geen Month-object maken denk ik. Want de date()-functies van PHP kunnen al erg veel dus kun je gewoon in je Date-object maken.
Klystr
klystr
13 jaar geleden
 
0 +1 -0 -1
Ik wachtte persoonlijk al een tijdje op zoiets, want zoals je zegt...veel mensen denken dat ze met een klasse al OOP gebruiken, terwijl dit verre van waar is.

Ik vind het erg goed dat je dit hebt gedaan, petje af en het ziet er goed uit ;-)
Kalle P
Kalle P
13 jaar geleden
 
0 +1 -0 -1
H? phperik wat toevallig hier hadden we t gister over. Phpnaabjeeeeeeeeeeeeeeeeeeeeee. Whahahha. Verhelderend. Ik denk dat iedereen wel eens in de mist gaat bij dit. Het is ook niet erg op heel diep te gaan met objecten in objecten te gooien, maar je maakt het wel mega dynamisch, overzichtelijk en het allerbest beheerbaar. Stel dat de manier van emaildressen noteren gaat veranderen, dan hoef je dus maar op 1 plek je code aan te passen en dat is in de emailvalidator klase.

dus dit doe jij onder werk tijd.

Tjallaballa
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Quote:
H? phperik wat toevallig hier hadden we t gister over.
Idd, en ik kon het niet meer uitstaan dat mensen 1000 regels in 1 class gooien en dan nog 2000 in een andere en dat "[OOP] xxx v1.0" noemen. Ik noem dat "trOOP v1.0" (op zn engels uitgesproken dan).
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Nog wat voorbeelden van een Validator_Email of Validator_Empty erbij, dan is het voorbeeld wat beter te begrijpen.

Hier is een voorbeeld van hoe de Request filter eruit zou KUNNEN zien:
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
<?php

class Berg_Request_filter
{
    protected $_waiting = array();

    public function __construct(Array $array)
    {

        $this->_waiting = $array;
    }


    public function filter()
    {

        $waiting = $this->_waiting;
        
        if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() == 1) {
            $waiting = array_map(array($this, '_undoMagic_quotes'), $waiting);
        }

        
        return array_map('trim', $waiting);
    }


    protected function _undoMagicQuotes($array)
    {

        $newArray = array();

        foreach($array as $key => $value) {
            $key = stripslashes($key);
            
            if (is_array($value)) {
                $newArray[$key] = $this->_undoMagicQuotes($value);
            }

            else {
                $newArray[$key] = stripslashes($value);
            }
        }

        return $newArray;
    }
}

?>
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Ik heb voorbeeld Validatie-adapters toegevoegd op de Praktijkpagina.

Hierbij zie je ook meteen waar een Interface handig voor is en hoe die lege objecten in de Validator::setValidator(string, object) werken.
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Ik ga mijn Filter script weer aanpassen. Werkt een stuk makkelijker met een object met interfaces. Wist niet dat je een Interface door kon geven als typehinting, snap nu een stuk beter het nut van interfaces :)

Zonder die mogelijkheid kan je nl gewoon kiezen je class geen interface te laten gebruiken, en dan klopt de boel niet meer ;)
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Ook al gebruik je die type hinting niet dan is het een interface nog steeds heel handig. Kijk maar eens naar de interfaces ArrayAccess en Iterator die PHP standaard in z'n pakket heeft zitten. Als je die implementeert in bijvoorbeeld data-objecten, dan kun je een object als array gebruiken. Je dwingt dus een standaard af. Vooral als je met meerdere mensen werkt is dit heel handig, maar dus ook om af te dwingen dat je geen fouten maakt.

Btw, ik had het stukje net weer iets meer aangepast en nu is 't voorlopig wel even klaar denk ik.
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Ja, ArrayAccess enzo zijn erg handig, maar zelf kan je niet zomaar iets dergelijk maken.
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Maar je kunt wel dingen afdwingen met een interface. Dan kun je namelijk in scripts waar je die objecten gebruikt er gewoon vanuit gaan dat bepaalde methods bestaan. Stel je maakt een interface voor plug-ins, dan weet je voortaan altijd hoe een plug-in in elkaar zit. Je kunt dan dus ook dynamisch alle plug-ins laden (bijv. vanuit een database). Je script die de plug-ins aanroept en afhandelt hoeft dan nooit aangepast te worden als er een plug-in bijkomt, omdat je al weet dat je bijvoorbeeld altijd call() of render() of iets dergelijks hebt.

Dus interfaces blijven onmisbaar bij een goed opgezette omgeving, vooral als je met meerdere mensen werkt of open source dingen maakt.
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Ja.

Al heb je ook Abstract. Die gebruik ik veel vaker, omdat ik dan alvast functies kan defineren. Net wat je nodig hebt ;)
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Ik gebruik ook vaker een abstracte klasse dan een interface, maar ik wilde in dit voorbeeld even zien hoe handig een interface kan zijn :)
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Ik ga even een 2e versie maken van mn filter, die plaats ik hier dan ff als hij klaar is ;)
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Je kunt 'm beter ergens apart posten. Ik wil hier juist zo min mogelijk code houden en er zijn voldoende voorbeelden nu.
Iltar van der berg
iltar van der berg
13 jaar geleden
 
0 +1 -0 -1
Nou ik bedoelde echter een linkje ;) hij word niet echt super klein ;)
(wil em aanbieden met wat standaard validators)
Jeroen Nieuwenhuisen
Jeroen Nieuwenhuisen
13 jaar geleden
 
0 +1 -0 -1
Sinds kort ben ik me eigen aan het ori?nteren op het gebied van object geori?nteerd programmeren, daarom ben ik de schrijver van deze tutorial zeer dankbaar voor het leveren van een bijdrage in mijn leerproces.

Ik ben wat aan het oefenen gegaan, maar ik wil even weten of ik op de juiste wijze bezig ben.

Ik ben nu bezig met een captcha script die uit drie klassen bestaat: Captcha, Code en Image. De Captcha klasse maakt een nieuw object Code, en extends de klasse Image. Volgens mijn gedachtegang is dit een goede wijze, een Captcha is namelijk ook een Image.

Maar wat vinden de OOP experts ervan?
Jelmer -
Jelmer -
13 jaar geleden
 
0 +1 -0 -1
Volgens mij is het wel een goeie aanpak.

Echter is het beter dit soort specifieke vragen in een topic op het forum te stellen zodat we daar verder kunnen praten over jouw specifieke probleem. Eventueel plaats je hier een link naar het topic zodat mensen het als voorbeeld terug kunnen vinden maar de gehele discussie hier in de reacties voeren lijkt mij niet een goed idee.
Harm
Harm
13 jaar geleden
 
0 +1 -0 -1
Kan iemand mij misschien vertellen hoe je met exceptions om moet gaan? Ik verdiep me namelijk nu een beetje in OOP.. een ik begrijp hier eerlijkgezegd geen snars van...
Jelmer -
Jelmer -
13 jaar geleden
 
0 +1 -0 -1
In de OOP sectie van het forum staan vrij veel leerzame topic. Zo ook omtrent exceptions:
- Exceptions gebruiken
- try...catch en if-else
en nog veel meer
Rudie dirkx
rudie dirkx
13 jaar geleden
 
0 +1 -0 -1
Wat ik heel raar vind, is dat je een exception throwt buiten je class. En zonder op te vangen. Dan heeft een exception natuurlijk weinig zin. Er zijn twee oplossingen (mijn favoriet is de eerste: geen exceptions):
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php

if ( !$validator->validate() ) {
    header('Location: terug naar form'); // of
    exit('Ongeldige waarden in het formulier. O.i.d.');
}


?>

Of je doet het wel met exceptions, die wordt dus gegooid IN de methode validate():
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
<?php

try {
    $validator->validate();
}

catch (ValidationException $e) {
    switch ( $e->getCode() )
    {
        case
ValidationException::EXCEPTION_CODE_MISSING_VALUE:
        // etc...
    } // of
    exit($e->getMessage());
}


?>

Beide zijn prima, je moet maar van exceptions houden, of niet. Ikzelf ben niet zo'n fan. PHP is zo handig om elk type te kunnen returnen, dus een FALSE betekent dat t niet goed is gegaan, zonder exception te gooien.

Verder snap ik niet dat je een STRING (bijv $_POST['naam'] of $_POST['email']) gaat vergelijken met/valideren dmv een object. Het ligt maar aan de moeilijkheid van je validator class natuurlijk, maar ik zou een paar regex in de class zetten (dat zijn dus strings) en POST waarden daarmee vergelijken. Als je POST vars arrays kunnen bevatten werkt dit niet meer, maar ik denk dat jouw methode in heel veel gevallen overkill is (een class per validatie(type)). Wel een potentieel goed OO voorbeeld.
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Quote:
Wat ik heel raar vind, is dat je een exception throwt buiten je class.
Dat blok code hoort logischerwijs ook in een class. Bij echt OOP zit alles in een class, dus dat stukje ook.

Maar als jij geen fan bent van exceptions dan ben ik heel benieuwd of je de essentie ervan wel ziet, blijkbaar niet. Je wilt juist je hele if/else/switch structuur voorkomen met exception. Met exceptions kun je er in je code vanuit gaan dat dingen goed gaan, en als het fout gaat vang je dat ergens anders op om vervolgens een nieuwe set handelingen te verrichten.

Mijn methode is in geen enkel geval overkill. Ik zou een tutorial moeten maken over het nut van object ge?rienteerd programmeren, want jij ziet het volgens mij niet. Stel ik vergelijk gewoon met regexjes dan krijg je weer zo'n hele zooi in 1 class met if's en else's en errorcodes en allemaal troep. Dat wil je juist voorkomen.

Jouw stukje code wat je net geeft is duidelijk niet in lijn met object ge?rienteerd programmeren. Je zal namelijk vrijwel nooit een header('Location') nodig hebben en al helemaal nooit een exit. Ik denk dat jij meer bezig bent met procedural programming in combinatie met wat objecten. De PHPhulp standaardwijze zeg maar, die ik hier probeer te doorbreken. Ik noem dat pOOP (procedural OOP :) )
Boris Mattijssen
Boris Mattijssen
13 jaar geleden
 
0 +1 -0 -1
Hallo PHPErik,

Allereerst, wat een top tutorial, ik heb nu al een veel beter inzicht in OOP gekregen.
Wat ik mij alleen nog even afvroeg, hoe maak jij een oop systeem waarbij je ook html nodig hebt.

Voorbeeldje:

Ik heb een tabelletje (html), met daarin een formulier, en daarin een dropdown die waardes bevatten die ik uit mijn class haal.
Hoe zou jij dit aanpakken?

Een aparte html class maken, of hoe moet ik dit voor mij ziet?

Ik hoop dat je het een beetje begrijpt.

Groeten,
Boris
PHP erik
PHP erik
13 jaar geleden
 
0 +1 -0 -1
Ja ik begrijp je denk ik heel goed. Het is gebruikelijk voor dit soort dingen een template engine te gebruiken. Bijvoorbeeld Smarty of Zend_View. Je maakt je website dan in templates en geeft vanuit PHP bepaalde variabelen mee zoals titel, berichten, etc. Bepaalde zaken zoals formulieren die misschien door een class worden gebouwd (zie bijvoorbeeld Zend_Form als voorbeeld) kun je ook meegeven in een variabele. Dit is soms een beetje tricky omdat je dan toch HTML met PHP aan het bouwen bent, maar als je een goede class gebruikt genereert deze puur de opbouw (HTML) maar niet de stijl. Nogmaals zie Zend_Form. Je hoeft Zend_Form niet te gebruiken, maar het illustreert goed hoe je ook een formulierclass in een templatesysteem kan "injecteren" op een nette manier.

In jouw geval kun je waarschijnlijk vrij simpel een template gebruiken die een array met dropdownopties meekrijgt uit PHP, zodat de template deze dropdown opbouwt aan de hand van die array. Zie Smarty's {foreach} en {section}.

Lees ook op de site van Smarty even wat hun principe is. Namelijk het scheiden van presentatie en logica. Templates zijn puur voor presentatie, maar bevatten wel geringe logica om bijvoorbeeld door een array te loopen. Op de site van Smarty staat dit principe vrij goed uitgelegd, maar je zult ermee aan de slag moeten om het in de vingers te krijgen.

Ik hoop dat dit je vraag beantwoordt.
Toby hinloopen
toby hinloopen
13 jaar geleden
 
0 +1 -0 -1
je moet wel ff de tijd nemen het goed door te lezen :P ik ben er niet veel wijzer van geworden :P
PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Steven Hack
Steven Hack
13 jaar geleden
 
0 +1 -0 -1
Mooie uitleg. Ik snap nu dat OOP gewoon een manier van scripten is, en niet van puur php.
Het is in ieder geval wel een stuk overzichtelijker. Mooi werk!

Om te reageren heb je een account nodig en je moet ingelogd zijn.

 
 

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.