mee eens? (leesvoer)

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 volgende »

Ozzie PHP

Ozzie PHP

17/03/2013 21:29:00
Quote Anchor link
Hallo mensen,

Ik kwam dit artikel tegen. Strekking: gebruik getters/setters in plaats van public properties. Er wordt grofweg gesteld dat je geen public properties moet gebruiken, omdat je daar eventuele set methods mee kunt overrulen, en omdat het makkelijker is om je systeem te onderhouden via getters en setters. Mee eens... of te kort door de bocht?

Hier het artikel:
http://blog.everymansoftware.com/2012/03/getset-methods-vs-public-properties.html

Voor de mensen die aan OOP doen, ik zou het leuk vinden als jullie een reactie geven. Werken jullie zelf met public properties of alleen met getters en setters?
Gewijzigd op 17/03/2013 21:29:23 door Ozzie PHP
 
PHP hulp

PHP hulp

28/11/2024 06:48:27
 
Wouter J

Wouter J

17/03/2013 21:37:53
 
Ozzie PHP

Ozzie PHP

17/03/2013 21:47:59
Quote Anchor link
Hehe, jij bent goed met de zoekfunctie Wouter ;)
Er zit zeker een stukje overlap in.

Ik hoop echter dat ik nu goede informatie heb gevonden waaruit EENDUIDIG blijkt of je wel of geen getters/setters moet gebruiken. Ik vind de argumenten in het artikel wel behoorlijk overtuigend, maar ben benieuwd of de OOP gebruikers het er mee eens zijn???

(Je hebt gelijk hoor dat ik het al vaak over dit onderwerp heb gehad. Ik dacht ook dat ik er 100% uit was... totdat ik gisteren door iemand aan het twijfelen ben gebracht omdat het direct aanspreken van public properties sneller is dan het gebruik van getters. En als het om snelheid gaat... je kent me inmiddels :) Daar ben ik gevoelig voor. En nu wil ik dus nog 1x voor mezelf duidelijk hebben wat ik moet doen. Gezien het snelheidsvoordeel neig ik naar public properties, maar als ik de argumenten in het artikel lees dan neig ik weer naar getters. Ik wil nu voor eens en voor altijd de knoop doorhakken... heeelluup!)
Gewijzigd op 17/03/2013 21:49:11 door Ozzie PHP
 
Willem vp

Willem vp

17/03/2013 23:45:13
Quote Anchor link
Ozzie PHP op 17/03/2013 21:47:59:
En als het om snelheid gaat... je kent me inmiddels :) Daar ben ik gevoelig voor.

Als je snelheid zo belangrijk vindt, waarom gebruik je dan OO? ;-)

OO is bedoeld voor abstractie, niet om snelle programma's te schrijven. Het argument dat je public properties moet gebruiken vanwege de snelheid is dus bedacht door iemand die het object 'bel' heeft horen luiden, maar niet weet waar de property 'klepel' hangt. Of zo. Ben slecht in spreekwoorden.

Aan de andere kant, als je object voornamelijk bestaat uit getters en setters, dan klopt je ontwerp ook niet; dan doe je alleen maar aan information hiding, en daar is OO een beetje een zwaar middel voor. Als ik het me goed herinner, móchten we tijdens mijn studie niet eens methods maken die alleen maar een get of set van een property deden.
Gewijzigd op 17/03/2013 23:48:21 door Willem vp
 
Ozzie PHP

Ozzie PHP

17/03/2013 23:50:26
Quote Anchor link
Hey Willem,

Dankjewel voor je reactie! Blij dat er iemand reageert :-)

Nee, klopt dat OO niet bedoeld is voor snelheid. Maar ik vind OO wel een prettige manier van werken, en ik wil dan voor mezelf de meeste snelheid eruit halen die erin zit.

Kun je eens uitleggen, of misschien een voorbeeld geven wat je bedoelt met jouw laatste opmerking? Dat snap ik niet helemaal.

Willem vp op 17/03/2013 23:45:13:
Aan de andere kant, als je object voornamelijk bestaat uit getters en setters, dan klopt je ontwerp ook niet; dan doe je alleen maar aan information hiding, en daar is OO een beetje een zwaar middel voor. Als ik het me goed herinner, móchten we tijdens mijn studie niet eens methods maken die alleen maar een get of set van een property deden.
 
Reshad F

Reshad F

18/03/2013 00:27:05
Quote Anchor link
Ozzie ik gebruik altijd getters en setters en wel door de volgende reden

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
<?php
class Rekening {
    
    private $saldo = 1000;
    private $bedrag;

    public function neemOp($bedrag) {

        $this->bedrag = $bedrag;
        if($bedrag < $this->saldo) {

            $this->saldo -= $bedrag;

            return sprintf('u heeft nog %01.2f euro op de bank', $this->saldo);
        }

        else {
            return sprintf('U heeft maar %01.2f euro op de bank', $this->saldo);
        }
        
    }


    public function stort($bedrag) {

        // hier je controle etc..


    }

}



$neemgeld = new Rekening();

echo $neemgeld->neemOp(80);

?>


Hoe zou jij het bovenstaande willen doen zonder een getter en een setter? ( op een veilige manier met controles )
Ik zou je gewoon aanraden alles private te houden. Het kan wel zo zijn dat je een paar regels meer code hebt maar het uiteindelijke doel van OOP is dat je straks gewoon kan zeggen

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php

    $neemgeld
= new Rekening();

    echo $neemgeld->neemOp(80);

?>


zonder na te denken over de rest van de klasse. ( en natuurlijk het hergebruik ervan )
als je OOP programmeert moet je naar mijn mening eerder kijken naar de manier van het programmeren ( dus OO ) dan te kijken naar de performance. als je het echt snel wilt hebben moet je procedurele code schrijven.
 
Ozzie PHP

Ozzie PHP

18/03/2013 00:37:27
Quote Anchor link
Reshad, thanks voor je voorbeeld :)

Als je naar jouw voorbeeld kijkt en $saldo zou een public property zijn, dan zou je bijv. dit kunnen doen:

$saldo = $this->saldo;

Als $saldo een private property is, zou je het zo moeten doen:

$saldo = $this->getSaldo();

Het 1e voorbeeld is sneller, maar het 2e voorbeeld is veiliger. In het 1e voorbeeld zou ik namelijk makkelijk het saldo kunnen veranderen.

Ik denk dat het inderdaad beter is om getters/setters te gebruiken in plaats van public properties. Ik vind het toch wat te veel risico.
Gewijzigd op 18/03/2013 00:40:39 door Ozzie PHP
 
Willem vp

Willem vp

18/03/2013 00:43:20
Quote Anchor link
Ozzie PHP op 17/03/2013 23:50:26:
Nee, klopt dat OO niet bedoeld is voor snelheid. Maar ik vind OO wel een prettige manier van werken, en ik wil dan voor mezelf de meeste snelheid eruit halen die erin zit.

Nu komen we op het gebied van de micro-optimalisatie, maar ik geloof dat ik snel moet bukken als ik dat woord noem. ;-)
Quote:
Kun je eens uitleggen, of misschien een voorbeeld geven wat je bedoelt met jouw laatste opmerking? Dat snap ik niet helemaal.

Pff... nu moet ik even een jaar of 20 terug in mijn geheugen, en ik heb er soms al moeite mee om 20 minuten terug te gaan... Maar goed, laat ik een poging wagen:

Laten we eerst vaststellen wat een object is: een zo natuurgetrouw mogelijke representatie van een al dan niet tastbaar begrip uit de werkelijkheid. De inhoud van een object kan in principe niet rechtstreeks benaderd worden; voor alle manipulaties op de inhoud moet gebruik gemaakt worden van messages. Een message is een boodschap die naar een object kan worden gestuurd en tot een bepaalde actie van dat object leidt.

Je zou kunnen beargumenteren dat het simpelweg getten of setten van een property eigenlijk geen actie van het object veroorzaakt. Er moet meer achter zitten.

Neem bijvoorbeeld als object een 4-kleurenpen. Als je daar een method set_color hebt met als parameter de kleur dan zal een set_color(zwart) niet alleen de zwarte stift uitschuiven. Hij zal eerst moeten kijken of er niet al een andere stift is uitgeschoven. Zo ja, dan moet die worden ingetrokken voordat de zwarte stift uitgeschoven kan worden.

Dat is ook meteen de reden dat public properties eigenlijk 'not done' zijn. Het object raakt dan het overzicht/de controle kwijt.

Overigens denk ik dat er altijd wel redenen te bedenken zijn om toch een 'simpele' get- of set-method te maken. In bovenstaand voorbeeld zou ik me goed kunnen indenken dat ik wil weten wat de huidige kleur is waarmee de pen schrijft. Aan de andere kant: wat heeft het voor nut om dat te weten, want als ik op basis van die wetenschap iets wil doen, moet ik dat toch via een method regelen. De logica om iets met die waarde te doen zou dus ín het object moeten zitten, en niet erbuiten.

Dat was volgens mij zo ongeveer de gedachte achter het niet mogen gebruiken van 'simpele' getters en setters. Bovendien werd je daardoor gedwongen om verder door te denken over het ontwerp van je classes en objecten.
 
Ozzie PHP

Ozzie PHP

18/03/2013 01:19:38
Quote Anchor link
Willem vp op 18/03/2013 00:43:20:
Nu komen we op het gebied van de micro-optimalisatie, maar ik geloof dat ik snel moet bukken als ik dat woord noem. ;-)

Hehehe... +1

Oké... ik probeer jouw gedachtengang met de pen hierboven een beetje te volgen, maar ik begrijp het nog steeds niet helemaal. Stel dat jouw pen verkrijgbaar is in 5 verschillende merken. Nu wil ik het merk weten van de huidige pen. We willen geen public properties gebruiken, dus we hanteren een method getBrand().

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
echo 'Het merk van uw pen is: ' . $this->getBrand();
?>

Het enige wat die getBrand() doet is dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
public function getBrand() {
  return $this->brand;
}

?>

Dit is dus een simpele getter. Maar waarom zou dat dan niet goed zijn? En hoe zou je anders het merk moeten opvragen? (Het enige alternatief is dan een public property, maar dat is ook niet goed toch?)
 
Willem vp

Willem vp

18/03/2013 08:25:32
Quote Anchor link
En dan komen we weer terug bij de vraag "wat zou je met die informatie willen doen?"
Wat voor nut heeft het om te weten wat voor merk pen je hebt? Als je ermee wilt schrijven, maakt het niet uit of het een Bic of een Parker is, of desnoods het huismerk van de Lidl.

Nu ga ik nog een stap verder: ik zou me kunnen voorstellen dat een pen van een bepaald merk properties heeft die pennen van een ander merk niet hebben. In dat geval zou je misschien zelfs subclasses Bicpen, Parkerpen en Lidlpen moeten maken. ;-)
 
Ward van der Put
Moderator

Ward van der Put

18/03/2013 09:35:08
Quote Anchor link
Leesvoer: er is een Property get/set syntax RFC die een andere PHP-syntaxis aanbeveelt en ook uitlegt waarom. Een property wordt hierbij gedefinieerd inclusief de eigen setter en getter.

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
<?php
class TimePeriod
{
    private $seconds;
 
    // Properties are implemented using the "property" keyword, just like functions/methods use the "function" keyword
    public property Hours
    {
        get { return $this->seconds / 3600; }
        set { $this->seconds = $value * 3600; } // The variable $value holds the incoming value to be "set"
    }
};


// Accessing the property is the same as accessing a class member
$time = new TimePeriod();
$time->Hours = 12; // Stored as 43200
echo $time->Hours; // Outputs 12
?>


Een eigenschap "is iets" en een methode "doet iets". Dat maakt een aanroep $time->Hours voor een eigenschap in mijn ogen netter en logischer dan de $time->getHours() die we nu zouden gebruiken.
 
Ozzie PHP

Ozzie PHP

18/03/2013 12:51:08
Quote Anchor link
Kan iemand het voorbeeld van Ward hierboven eens checken? Bij mij werkt het namelijk niet. Bij jullie wel??


Willem vp op 18/03/2013 08:25:32:
En dan komen we weer terug bij de vraag "wat zou je met die informatie willen doen?"
Wat voor nut heeft het om te weten wat voor merk pen je hebt?

Ja, maar dat is toch een vreemde vraag die je nu stelt? Laten we dan in plaats van een pen een auto nemen. Stel we zitten op de website van een autogarage en ik wil een auto kopen van een bepaald merk. Dan moet een class toch gewoon het merk van de auto kunnen teruggeven?
 
Ward van der Put
Moderator

Ward van der Put

18/03/2013 13:08:35
Quote Anchor link
Ozzie PHP op 18/03/2013 12:51:08:
Kan iemand het voorbeeld van Ward hierboven eens checken? Bij mij werkt het namelijk niet. Bij jullie wel??
Ozzie, deze RFC is een voorstel voor een verbetering van PHP. Ik heb hem hier aangehaald om te laten zien dat je niet de enige bent die vraagtekens zet bij de huidige PHP-implementatie van getters en setters. En om te laten zien hoe het beter zou kunnen.
 
Ozzie PHP

Ozzie PHP

18/03/2013 13:10:37
Quote Anchor link
Ah oke... dan heb ik er nu dus nog niks aan. Gaat dit er wel ooit komen dat jij weet?

Snap jij overigens wat Willem bedoelt met het opvragen van een merk?
 
Ward van der Put
Moderator

Ward van der Put

18/03/2013 14:15:25
Quote Anchor link
Vooral de knelpunten die in de RFC worden genoemd, zijn verhelderend. Je zou het haast een "fundamenteel probleem" in PHP-OO kunnen noemen. Maar of de verbeteringen ooit in PHP zullen terug te vinden zijn? Misschien? Hopelijk?

Willem bedoelt waarschijnlijk dat een klasse met de eigenschappen Foo en Bar niet automatisch een setFoo() met getFoo() en een setBar() met een getBar() heeft. De vanzelfsprekendheid van dit automatisme is aanvechtbaar; de methoden moeten hun bestaansrecht ontlenen aan iets waarvoor je ze kunt/moet gebruiken. Je ontwerpt een model met een reden; je bouwt een klasse met een doel.

Die complexiteit proef je als je een setColor() en een setBrand() hebt maar een bepaald merk pen niet in alle kleuren verkrijgbaar is. Naïeve setters en getters zijn dan slecht bruikbaar. En zou je een class ParkerPen extends Pen gebruiken, dan gooien ze mogelijk roet in het eten via inheritance.

Dat brengt je dus bij de vraag welk doel zo'n getBrand() nu eigenlijk dient. Is het een display-methode voor een echo $object->getBrand()? Of heb je de methode voor iets anders ingebouwd, bijvoorbeeld voor het intern sturen van je $this->setColor(...)? Dát is de hamvraag: "Wat zou je met die informatie willen doen?"
 
Ozzie PHP

Ozzie PHP

18/03/2013 14:24:21
Quote Anchor link
Dankjewel voor je uitleg Ward.

Willem stelde het volgende: "Als ik het me goed herinner, móchten we tijdens mijn studie niet eens methods maken die alleen maar een get of set van een property deden."

En hier ging mijn vraag dus precies over. Bovenstaande opmerking suggereert dat je geen getters mag gebruiken die selchts een property teruggeven. En daar ging mijn vraag dus over... hoezo zou dat niet mogen? Dat getBrand() is hier slechts een voorbeeldje. Geen idee of je dat in de praktijk nodig hebt. Maar goed... laten we bijvoorbeeld even terugpakken op het voorbeeld van Reshad. Stel een gebruiker vraagt z'n banksaldo op. Dit banksaldo is door een private setter geset, en zal moeten worden opgehaald door een public getter. Mee eens? (Uiteraard kun je van het saldo een public property maken, maar dat lijkt me niet wenselijk omdat het saldo dan van buiten de class kan worden gewijzigd.) Als ik nu het saldo opvraag, dan is het enige wat die method doet, de waarde van de property retourneren. En volgens de opmerking van Willem zou dat dus niet goed zijn. Dat is dus waar mijn "verwarring" vandaan komt. Waarom zou een getter die een property retourneert per definitie niet goed zijn?
 
Ward van der Put
Moderator

Ward van der Put

18/03/2013 17:21:45
Quote Anchor link
Ozzie PHP op 18/03/2013 14:24:21:
Willem stelde het volgende: "Als ik het me goed herinner, móchten we tijdens mijn studie niet eens methods maken die alleen maar een get of set van een property deden."

Je kunt daarvoor verschillende redenen aanvoeren.

• Een best practice is per definitie nooit een bad practice en al helemaal geen evil practice. Als je een private $PinCode openzet met een public function getPinCode(), barst iedereen spontaan in tranen uit. Maar dan moet je ook niet luid gaan staan applaudisseren als iemand een willekeurige private $Foo op de automatische piloot begint met een public function getFoo(). Er is niets vanzelfsprekends aan dit prototype:

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
<?php
class Foo
{
    private $Foo;

    // Naïeve setter
    public function setFoo($value)
    {

        $this->Foo = $value;
    }


    // Naïeve getter
    public function getFoo()
    {

        return $this->Foo;
    }
}

?>


• Je kunt zichtbaarheid niet meer goed regelen. Een private $Foo is niet meer volledig private als deze een public function setFoo() en een public function getFoo() heeft. Private en public mengen niet goed als die voor een eigenschap anders zijn dan voor methoden die uitsluitend aangrijpen op die eigenschap.

• Je omzeilt de standaardwerking van PHP's magische methoden __get() en __set(). Dat is overigens een van de bijeffecten die de RFC hoopt op te lossen.

• Het is nadelig voor de performance, omdat een naïeve methode slechts interne standaardfunctionaliteit nabootst. Een methode die niets toevoegt, heeft geen toegevoegde waarde. Of anders gezegd: je programmeert iets dat er al is en dat is wel het laatste dat je bij OOP wilt doen.

• Met naïeve setters en getters adresseer je een eigenschap in wezen nog steeds rechtstreeks of "blind" en dat wil je vaak helemaal niet. De klasse wordt met naïeve setters en getters inhoudelijk niet wezenlijk anders of beter gebruikt dan wanneer je een public $Foo zou hebben: alleen de syntaxis verandert.

• Op het niveau van een applicatie werkt het nodeloos omslachtig gebruik van de klasse als datacontainer in de hand. Als je al $x = 'y' weet, hoef je dit niet met $object->setFoo($x) op te slaan om het later met $z = $object->getFoo() op te vragen. De setFoo() biedt je slechts schijnzekerheid als het een naïeve setter is: er lijkt iets met $x te gebeuren maar dat is niet zo.

Maar dan hebben we het dus uitdrukkelijk alleen over naïeve setters en getters. Zodra een methode iets met een eigenschap doet, is deze niet langer naïef. Een getter die een property retourneert, is dus niet per definitie slecht!
 
Ozzie PHP

Ozzie PHP

18/03/2013 17:36:01
Quote Anchor link
Oké, ik begrijp wel wat je bedoelt. Het "zomaar" gebruiken van getters en setters is niet per definitie goed. Daar heb je inderdaad gelijk in. Een private pincode die je kunt opvragen via een public getter is inderdaad niet handig. Volledig mee eens. En naïeve setters... tja, daar kan ik je ook alleen maar gelijk in geven. Je kunt dan beter rechtstreeks in de construct iets setten. Echter, toch zou ik niet een property rechtstreeks willen kunnen setten (zonder setter), omdat je dan alle controle kwijt bent. Je kunt eventueel aanwezige setters overrulen en dat lijkt me geen goede zaak. Ik ben geen voorstander van public properties omdat je dan alle controle kwijt bent. Je kunt ze op een verkeerde manier wijzigen, overschrijven, of zelfs unsetten. Daarom vind ik het wel goed om daar public getters voor te gebruiken.

Magic getters en setters zou ik zelf overigens nooit gebruiken omdat ze enorm traag zijn (doe maar eens een benchmark).

Als dat RFC verhaal doorgaat dan wordt het een stuk makkelijker, maar zal dat ooit gebeuren?
 
Wouter J

Wouter J

18/03/2013 17:43:29
Quote Anchor link
Quote:
Als dat RFC verhaal doorgaat dan wordt het een stuk makkelijker, maar zal dat ooit gebeuren?

Ja, hij stond op het programma voor PHP5.5, maar is toch wat vertraagd, grote kans dat ie in PHP5.6 zit.
 
Ward van der Put
Moderator

Ward van der Put

18/03/2013 17:50:56
Quote Anchor link
Je moet het misschien praktischer aanvaren. Zo'n getBrand() schrijf je pas als je de methode ergens voor nodig hebt en nooit enkel en alleen omdat je class een property $Brand heeft. Dan weet je ook precies waartoe die methode dient en hoe de methode gebruikt mag/moet worden.
 
Wouter J

Wouter J

18/03/2013 18:04:52
Quote Anchor link
Offtopic:

Omdat het ook leuk is om te kijken hoe andere talen dan de standaard C talen het aanpakken: Ruby gebruikt de zogenaamde accessors. Hiermee kun je aangeven of een property alleen leesbaar is (of alleen schrijfbaar) of allebei. Er wordt dan zo'n standaard getter/setter gemaakt (merk op dat alle properties private zijn in ruby):
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
class Person

    # maakt getter aan
    attr_reader :name, :gender

    def initialize
        @male_names ['jan', 'ben', 'klaas', ...]
        @female_names ['nienke', ...]
    end

    # setter voor naam
    def name= name
        @name = name

        # guess the gender
        if @male_names.include? name
            @gender = 'male'
        elsif @female_names.include? name
            @gender = 'female'
        end
    end

    # gender setter
    def gender= gender
        if ['male', 'female'].include? gender
            @gender = gender
        else
            raise "I thought a human can only be a male or female, #{gender} given"
        end
    end

end

# In gebruik
jan = Person.new
jan.name = 'jan'

puts jan.gender # 'male'

nienke = Person.new
nienke.name = 'nienke'

puts nienke.gender # 'female'
 

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.