dubbelop of niet?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 volgende »

Ozzie PHP

Ozzie PHP

26/02/2013 01:14:03
Quote Anchor link
Hallo,

Stel ik heb deze class:

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
class FooBar {

    private $foo;

    public function __construct(Foo $foo) {
        $this->setFoo($foo);
    }


    private function setFoo(Foo $foo) {
        $this->foo = $foo;
    }

}

?>


Nu vraag ik me het volgende af.

In de __construct method geef ik aan dat $foo een object moet zijn van het type Foo. Vervolgens doe ik in de private method setFoo precies hetzelfde. Ook hier geef ik aan dat een object van het type Foo verwacht wordt. Nu twijfel ik tussen deze 2 beredeneringen:

a) dit is dubbelop, het is voldoende om alleen in de __construct method aan te geven dat een object van het type Foo wordt verwacht.

b) zo is het juist duidelijk, omdat je zowel in de __construct method als setFoo method precies kunt zien welk type object er wordt verwacht.

Graag jullie mening. Wat is juist, beredenering a of b?
 
PHP hulp

PHP hulp

28/11/2024 10:49:16
 
Frank Nietbelangrijk

Frank Nietbelangrijk

26/02/2013 01:19:44
Quote Anchor link
B. (kort antwoord, ik weet t)
 
Ozzie PHP

Ozzie PHP

26/02/2013 01:22:34
Quote Anchor link
Kort maar duidelijk ;-)
Thanks!
 
Erwin H

Erwin H

26/02/2013 09:07:54
Quote Anchor link
Opvallend dat je optie c niet noemt: wel in de setter niet in de construct.
Volgens mij zou de setter moeten bepalen wat er geset mag worden en daar zou het dus in elk geval moeten staan.

Dat gezegd hebbende, ik ga mee met Frank. Het is niet dubbelop, voor beide methods geldt dat het een Foo object moet zijn. Dat de ene de andere aanroept is daarbij van ondergeschikt belang in mijn ogen.
 
TJVB tvb

TJVB tvb

26/02/2013 09:35:37
Quote Anchor link
Het zou onlogisch zijn om het wel bij je setter maar niet bij je constructor aan te geven. Dan lijkt het alsof je constructor meer accepteert terwijl dat niet het geval is. En je private methode gebruik je op meer plekken (anders is die misschien overbodig) waardoor het handig/netjes/wenselijk is om het daarbij ook aan te geven.
 
Wouter J

Wouter J

26/02/2013 10:51:06
Quote Anchor link
Ik ben het eens met B en Erwin's C.

Ja, het is theoretisch gezien dubbelop om het zowel bij de constructor als bij de setter in te stellen.
Ja, het is totaal verkeerd om het wel bij de constructor en niet bij de setter te doen.
Ja, het is niet overzichtelijk voor de constructor om het alleen bij de setter te doen.

Mijn oplossing: PHPdocs!!!

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 Foo
{
    /**
     * @var Cat
     */

    private $bar;

    /**
     * @param Cat $bar
     */

    public function __construct($bar)
    {

        $this->setBar($bar);
    }


    public function setBar(Cat $bar)
    {

        $this->bar = $bar;
    }
}

?>
 
Ward van der Put
Moderator

Ward van der Put

26/02/2013 11:30:49
Quote Anchor link
Of een namespace als je een Barbapappa als Bar wilt gebruiken:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
namespace FooBar;
use Ozzie\Framework\Barbapappa as Bar;
?>
 
Wouter J

Wouter J

26/02/2013 11:32:16
Quote Anchor link
Ward, ja, maar daar gaat het nu totaal niet over...
 
Ward van der Put
Moderator

Ward van der Put

26/02/2013 11:55:52
Quote Anchor link
Wouter J op 26/02/2013 11:32:16:
Ward, ja, maar daar gaat het nu totaal niet over...
Wel als je Bar op meerdere plaatsen expliciet maakt, want dan heb je alleen in de kop use Ozzie\Framework\Barbamamma as Bar; nodig wanneer je later liever Barbamamma dan Barbapappa gebruikt als Bar.

De vraag was immers of wat dubbelop is. Een nieuwe Bar met zoeken en vervangen op meerdere plaatsen moeten implementeren voorkom je met use. Dat is namelijk pas echt dubbelop en bovendien gevoelig voor fouten.
 
TJVB tvb

TJVB tvb

26/02/2013 11:57:37
Quote Anchor link
@Wouter J, fatsoenlijke phpdoc is inderdaad een must. Maar nu mis je zelf de typehinting in de constructor. Dat was toch niet je bedoeling?
 
Erwin H

Erwin H

26/02/2013 11:59:54
Quote Anchor link
Strict genomen is het genoeg om de typehinting in de setter alleen te plaatsen. De setter bepaalt namelijk wat er wel en niet geset mag worden, niet de constructor. Mocht je dan iets anders meegeven dan zal de setter alsnog de foutmelding geven.
 
Ozzie PHP

Ozzie PHP

26/02/2013 14:20:22
Quote Anchor link
Dank voor jullie reacties.

Ik vind de C optie... alleen in de setter aangeven wel type object het moet zijn enigszins vreemd. Ik snap de beredenering dat de setter bepaalt wat het moet zijn, maar de waarde die vanuit de constructor wordt doorgegeven mag niks anders zijn dan een object van het type Foo. Dan is het toch raar dat je daar alles toestaat?

Ik gebruik nu een aparte setFoo functie. Maar ik had ook vanuit de constructor gelijk dit kunnen doen:

$this->foo = $foo;

Dan had je toch ook verplicht een obejct van het type Foo nodig gehad?

Je weet dat de $foo vanuit de constructor per se een Foo object moet zijn, dus waarom het daar dan ook niet meteen verplicht stellen?
 
Wouter J

Wouter J

26/02/2013 14:23:28
Quote Anchor link
Quote:
Je weet dat de $foo vanuit de constructor per se een Foo object moet zijn, dus waarom het daar dan ook niet meteen verplicht stellen?

Omdat het niet de taak is van de constructor om te beslissen wat $this->foo bevat en wat er mee gedaan wordt als het een verkeerde waarde bevat.

Jij bent nu aan het scripten volgens mijn setter beleid, maar bent nog aan het denken volgens het constructor beleid. Dat werkt natuurlijk niet :)
 
Ozzie PHP

Ozzie PHP

26/02/2013 15:03:54
Quote Anchor link
Oké, ik zou het in de construct weg kunnen halen... maar is het allemaal niet wat raar?

Laat ik eens een praktijk voorbeeld geven...

Stel we hebben een fabriek die auto's in elkaar zet van het merk BMW. Om die auto's in elkaar te zetten wordt de fabriek bevoorraad door een extern bedrijf. Dit externe bedrijf levert ook nog onderdelen aan andere fabrieken van andere merken.

Op een mooie zonnige dag rijdt de vrachtwagen van het externe bedrijf naar de BMW fabriek, gevuld met onderdelen... voor Opel auto's! Oeps... foutje! De vrachtwagen met Opel onderdelen komt bij de poort van de BMW fabriek (let op, dit is de __construct functie). De lading wordt niet gecontroleerd en de vrachtwagen mag doorrijden. Het fabrieksterrein is groot en de vrachtwagen moet een paar kilometer verder rijden. Na 15 minuten bereikt hij de fabriekshal, parkeert zijn vrachtwagen tegen het laad-dock. Een ploeg van 10 medewerkers gaat de vrachtwagen uitladen. Alle onderdelen worden op pallets gestapeld en stuk voor stuk naar de machine gebracht waar ze moeten worden verwerkt. We zijn inmiddels anderhalf uur verder en 20 mensen hebben zich nu in totaal al met de vracht beziggehouden. Dan zet een machinewerker de machine aan en pakt een van de onderdelen erbij. "Hé!" roept hij, "dit zijn helemaal geen BMW onderdelen!" Het productieproces wordt onmiddelijk stopgezet en de BMW fabriek heeft een hoop schade opgelopen.

Was het dan niet handiger geweest als we direct aan de poort al even hadden gecontroleerd of in de vrachtwagen van het externe bedrijf wel de juiste (BMW) onderdelen zaten?
 
Erwin H

Erwin H

26/02/2013 15:18:25
Quote Anchor link
Leuk verhaal.... maar ik mis de analogie met je code.
In je code wacht je niet anderhalf uur lang (nog niet eens anderhalve miliseconde) tot je de setter aanroept. Zodra je het object dus aanmaakt krijg je direct een foutmelding om je oren. Omdat het in de constructor fout gaat (ook al loopt het dan nog via een setter) wordt het object niet eens aangemaakt (je krijgt een fatal error). Wat is het verschil met het typehinten in de constructor?

De class is verantwoordelijk voor zijn eigen doen en laten en moet er voor zorgen dat het ofwel goed kan werken, ofwel om hulp roept via een exception. Dat gebeurt in dit geval. Als je een verkeerde variabele meegeeft zal het object niet worden aangemaakt.
 
Wouter J

Wouter J

26/02/2013 15:22:16
Quote Anchor link
Goed, dat is de echte wereld. Nu de programmeer wereld, want je kan in je voorbeelden natuurlijk ook overdrijven.

We hebben een OpenComponents class. Die geven we mee aan BmwFactory#construct. Deze geeft deze waarde direct door aan BmwFactory#setComponents. Die komt er direct achter dat de waarde verkeerd is en geeft dat direct aan. Nog voor er ook maar iets 'uitgeladen' is of voordat er '15 minuten rij tijd' aan vooraf is gegaan. Al met al maakt het misschien 1/1000 nanoseconde uit, dat gaat Bmw echt niet merken in hun afzet.
 
Ozzie PHP

Ozzie PHP

26/02/2013 15:30:53
Quote Anchor link
Uiteraard is het een voorbeeld... en uiteraard is het overdreven. Maar dat moet af en toe om een punt duidelijk te maken..

Waar het mij om gaat is dit...

Als ik iets meegeef aan de constructor zie ik gelijk dat er een bepaald object wordt verwacht. Ik hoef dan niet eerst in die class te gaan kijken. Jullie geven het dan aan in de PHPDoc, maar dat vind ik zelf niet handig. Mijn vraag is dan ook, wat is er "fout" om het aan de poort (__construct) gelijk even te controleren? Dit zorgt mijns insziens alleen maar voor extra duidelijkheid juist.
 
Wouter J

Wouter J

26/02/2013 15:36:53
Quote Anchor link
Precies wat ik zeg, dit is niet de taak van de constructor. De setter bepaald wat er wel en niet in zijn property mag, een constructor moet daar niks over te zeggen hebben.

Als je zo'n ik-ben-beter-dan-mijn-developer-editor hebt (met autocompletion enzo) is PHPdoc vaak ook gesupport, waardoor het even duidelijk wordt als dat je typehints geeft. Want om typehints te zien zonder zo'n ik-ben-beter-dan-mijn-developer-editor moet je ook in de broncode kijken.

Als je het echt duidelijk wilt maken dan sla je die hele constructor over en ga je methods gebruiken als setComponentsWhichAcceptsOnlyABmwComponentsClassWhichImplementsTheComponentsInterfaceAndHasAMethodWhichIsCalledGetComponentsSoThatWeCanUseThoseComponentsToCreateYourCar. Dan weet je zeker dat je nooit meer fouten gaat maken...
Gewijzigd op 26/02/2013 15:37:46 door Wouter J
 
Ozzie PHP

Ozzie PHP

26/02/2013 15:46:36
Quote Anchor link
Dussss... :-/
 
Kris Peeters

Kris Peeters

26/02/2013 16:04:37
Quote Anchor link
Mag ik nog even opmerken dat php niet de ideale taal is om uit te leggen waarom er (bepaalde) OOP-principes zijn.

Php handelt altijd alles af in 1 ruk.
Alles wat met een object gebeurt, gebeurt nanoseconden nadat de constructor is uitgevoerd.

Vergelijk even met een windows applicatie; een GUI met formulier.
Daar kan je dus een object aanmaken in het begin.

user = new User();
user->init(); // voer hier dingen uit die sowieso moeten gebeuren

En naar mate de gebruiker iets invult, dikt de informatie van het object aan. Alles is dan event driven

user->setName( imputField.value )

In php heb je de luxe om alles te herschikken. Je hebt sowieso alle gegevens; dus of het in de constructor gebeurt; via setters; met een init(); ... het is voornamelijk een kwestie van smaak.
Gewijzigd op 26/02/2013 16:16:57 door Kris Peeters
 
Erwin H

Erwin H

26/02/2013 16:12:31
Quote Anchor link
Ozzie PHP op 26/02/2013 15:30:53:
Als ik iets meegeef aan de constructor zie ik gelijk dat er een bepaald object wordt verwacht. Ik hoef dan niet eerst in die class te gaan kijken. Jullie geven het dan aan in de PHPDoc, maar dat vind ik zelf niet handig. Mijn vraag is dan ook, wat is er "fout" om het aan de poort (__construct) gelijk even te controleren? Dit zorgt mijns insziens alleen maar voor extra duidelijkheid juist.

Van theorie weer terug naar praktijk.
optie a) je hebt setters en getters die alle verantwoordelijkheid nemen voor het setten en getten van de properties, ook intern.
optie b) een class moet autonoom kunnen werken, maar intern hoeft niet alles met setters en getters te gebeuren.

Zoals al eerder gemerkt (in een ander topic) is Wouter van categorie a en in dat geval bepaalt de setter dus welke type object er geset moet worden. De constructor moet daarvan afblijven. Als je namelijk morgen bepaalt dat er ook een ander type mag worden gebruikt dan moet je naast de setter ook de constructor aanpassen en dat wil je nu net niet.

Ik ben meer van optie b. Wat mij betreft hoeft het binnen een class niet allemaal 100% op die manier geregeld te worden. Ik zou dus wel ook in de constructor de type hint meegeven. Waarschijnlijk zou ik dan in de constructor ook direct het property setten en niet via de setter.

a beter dan b? Of andersom? Ligt eraan wat je keuze is. Voor beide valt wat te zeggen en je hebt voor beide argumenten voor en tegen.

Wat jij dus moet doen.... is een biertje pakken en achterover hangend de finale keuze maken in welk kamp je gaat zitten, voor de komende tijd dan ;-)
 

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.