class constants
Een (hoop ik) simpel vraagje. Waar zijn class constants eigenlijk voor bedoeld? In sommige gevallen is het vrij duidelijk. Stel je hebt een class en die class moet 5 producten tonen, dan zeg je:
const AMOUNT = 5;
Maar, nu vraag ik me af of je in de nu volgende situatie ook class constants behoort te gebruiken. Stel we hebben een class Foo, en class Foo slaat wel eens gegevens op. Deze gegevens worden altijd opgeslagen in directory "/foobar/bar". Is het dan de bedoeling dat je deze directory in een constante opslaat? Zo dus:
Code (php)
Zouden jullie hier een constante voor gebruiken (zoals in het voorbeeld) of zouden jullie de directory gewoon hardcoded in de method zetten. Dus zo:
Code (php)
Graag jullie reactie.
Gewijzigd op 14/10/2013 12:14:46 door Ozzie PHP
Als je nou 'static::DIRECTORY' zou gebruiken dan kan je in child classes die constante overschrijven en door 'static' te gebruiken in plaats van 'self' zal de ook echt de overloaded constante gebruikt worden.
Code (php)
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
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
<?php
class Foo {
const DIRECTORY = '/foobar/bar';
public function save($data) {
file_put_contents(static::DIRECTORY, $data);
}
}
class Miauw extends Foo {
const DIRECTORY = 'miauwwoef/miauw';
// hier meer code die dingen toevoegt/iets anders wijzigt dan de opslag locatie.
// anders verdient het waarschijnlijk geen eige class
}
$foo = new Foo;
$miauw = new Miauw;
// vanaf PHP 5.3.0 en hoger, voor lagere versies zou je een getter aan moeten maken.
// maar sinds jij 5.5 gebruikt zit je goed.
// http://php.net/manual/en/language.oop5.constants.php
var_dump($foo::DIRECTORY, $miauw::DIRECTORY);
?>
class Foo {
const DIRECTORY = '/foobar/bar';
public function save($data) {
file_put_contents(static::DIRECTORY, $data);
}
}
class Miauw extends Foo {
const DIRECTORY = 'miauwwoef/miauw';
// hier meer code die dingen toevoegt/iets anders wijzigt dan de opslag locatie.
// anders verdient het waarschijnlijk geen eige class
}
$foo = new Foo;
$miauw = new Miauw;
// vanaf PHP 5.3.0 en hoger, voor lagere versies zou je een getter aan moeten maken.
// maar sinds jij 5.5 gebruikt zit je goed.
// http://php.net/manual/en/language.oop5.constants.php
var_dump($foo::DIRECTORY, $miauw::DIRECTORY);
?>
Het hangt er vanaf of je nog andere dingen met die constante wilt kunnen doen. Als je ergens anders in je code base een methode hebt die de locatie nodig heeft waar Foo zijn spullen opslaat, dan is een constante gebruiken beter dan twee keer een path te hardcoden.
Mocht meerdere objecten willen hebben met de zelfde functieonaliteit als Foo maar voor verschillende paths dan moet je jezelf even afvragen of het niet beter is om het een configuratie optie te maken i.p.v. het voorbeeld hier boven. Vergeet dan geen getter te maken.
Ik wist dus niet dat je een constante kon overschrijven. Is dat iets nieuws? Wat zegt dat "static" dan eigenlijk?
Kijk, waarom ik dus dacht dathet goed is om in zo'n geval een constante te gebruiken, is omdat je dan alle "variabele" info buiten je code kunt houden. In dit geval is de directory een variabele factor (het had namelijk ook een andere directory kunnen zijn). Mocht je dan een keer de directory willen aanpassen, dan hoef je alleen de constante aan te passen, en hoef je niet daadwerkelijk in de code te gaan spitten.
self wordt dan namelijk gebruikt in de context van class Foo en dan dus vervangen worden door Foo::DIRECTORY.
static wordt gebruikt in de context van class/object gebruikt tijdens het aanroepen. Tenzij je een class final declareert weet je dus niet van te voren wat de context is.
PS. dan ben ik in de war met iemand anders wat betreft je PHP versie :p
Maar wat vind je van mijn eerdere redenatie? Om dus door middel van constanten de "variabelen" buiten de code te houden?
Dus in je code (method) geef je aan dat je een directory nodig hebt, maar buiten de code geef je via een constante aan om welke directory het gaat. Op deze manier krijg je dus geen variabele data in je code. Snap je wat ik bedoel te zeggen?
self houd dus in de methode/variabele/constante van de class waarin je het gebruikt of een van zijn ancestors (via inheritance), in die volgorde.
static houd dus in de methode/variabele/constante van de class die je aanroept, de class waarin je het of een van zijn ancestors (via inheritance), in die volgorde.
Veel voorbeelden zijn te vinden op http://php.net/manual/en/language.oop5.late-static-bindings.php
Tussen de comments zitten ook goede voorbeelden.
Gewijzigd op 14/10/2013 15:01:03 door Dos Moonen
Oké, maar "static::iets" werkt ook, dus dat maakt dan niet uit toch? Maar als ik in dit geval gewoon self gebruik dan klopt het toch?
Al met al nog geen antwoord op mijn vraag...
"Maar wat vind je van mijn eerdere redenatie? Om dus door middel van constanten de "variabelen" buiten de code te houden?
Dus in je code (method) geef je aan dat je een directory nodig hebt, maar buiten de code geef je via een constante aan om welke directory het gaat. Op deze manier krijg je dus geen variabele data in je code. Snap je wat ik bedoel te zeggen?"
Ozzie PHP op 14/10/2013 15:07:04:
"Maar wat vind je van mijn eerdere redenatie? Om dus door middel van constanten de "variabelen" buiten de code te houden?
Dus in je code (method) geef je aan dat je een directory nodig hebt, maar buiten de code geef je via een constante aan om welke directory het gaat. Op deze manier krijg je dus geen variabele data in je code. Snap je wat ik bedoel te zeggen?"
Dus in je code (method) geef je aan dat je een directory nodig hebt, maar buiten de code geef je via een constante aan om welke directory het gaat. Op deze manier krijg je dus geen variabele data in je code. Snap je wat ik bedoel te zeggen?"
Persoonlijke voorkeur + hangt van de situatie af. Je voorbeeld is zo slecht dat je er eigenlijk niks zinnigs over kan zeggen, aangezien je bij een class dat een file savet in een directory eigenlijk nooit de directory als constante wilt hebben (maar via een setter)
In dit geval gaat het om een class die altijd iets moet ophalen in een vaste directory. Die directory is onderdeel van een systeem en hoeft in dit specifieke geval niet geset te worden. Maar het gaat erom of het slim is om dit soort data buiten de code te houden.
Ander voorbeeld dan, speciaal voor jou ;)
Stel je verkoopt producten, en (vraag me niet waarom) je wil tijdelijk iedere productnaam suffixen met een text-string, bijv. '-MadeByNOLot!';
Dan kun je dit hardcoded in je method zetten:
... of je gaat een constante gebruiken:
Code (php)
Zijn constanten hier voor bedoeld is mijn vraag. Ik vind het een mooie manier om "data" los te koppelen van de code, maar is dit gebruikelijk vraag ik me af.
Gewijzigd op 14/10/2013 15:34:31 door Ozzie PHP
Ik kan dus niet met zekerheid zeggen of het in jouw geval uitmaakt of niet, al vermoed ik van niet.
Wat betreft je vraag, als er naast de save method nog een method van Foo dat path nodig heeft kan het het waard zijn. Een paar paths hardcoden in een bestand is zeker niet het ergste om aan te passen, daar hebben editors een search & replace optie voor. Maar als je het path buiten die class nodig hebt is het waarschijnlijk wel een goede reden om er een constante van te maken als het path niet configureerbaar is.
Dos Moonen op 14/10/2013 15:44:56:
Gebruik 'static' wanneer children het mogen overloaden, daar komt het op neer. Elke 'self' kan je zoals ik al zei in principe vervangen door de class naam van de class waarin de 'self' voorkomt. Voor 'static' is dit niet het geval. Als je dat zou doen kan het zijn dat kan het zijn dat dingen niet meer werken zoals ze horen te werken. Wanneer je 'self' zou vervangen door de class naam zal zoiets voor zover ik weet nooit voorkomen.
Ik kan dus niet met zekerheid zeggen of het in jouw geval uitmaakt of niet, al vermoed ik van niet.
Ik kan dus niet met zekerheid zeggen of het in jouw geval uitmaakt of niet, al vermoed ik van niet.
Dos Moonen op 14/10/2013 15:44:56:
Wat betreft je vraag, als er naast de save method nog een method van Foo dat path nodig heeft kan het het waard zijn. Een paar paths hardcoden in een bestand is zeker niet het ergste om aan te passen, daar hebben editors een search & replace optie voor. Maar als je het path buiten die class nodig hebt is het waarschijnlijk wel een goede reden om er een constante van te maken als het path niet configureerbaar is.
Thanks! In dit specifieke geval heb ik het path maar in 1 method nodig en hoeft het niet van buitenaf te worden aangeroepen.
De vraag is dan dus of het nuttig en/of gebruikelijk is om het in een constante te zetten. Het enige dat ik in feite doe, is dus dat ik de naam van de directory niet in de method zelf zet, maar (middels een constante) bovenaan de class, buiten de code. Ik vind het ergens wel mooi, omdat je dan geen "data" in de method hebt staan, maar ik vraag me dus nog steeds af of het gebruikelijk is.
Ik vind het dan onnodig. Ook zijn constante altijd public, dus 'foobar/foo' zal dan zichtbaar zijn buiten de context van die methode, waar dus blijkbaar geen enkele reden voor is.
Maar dan wel nog een laatste tegenvraag. In wat voor gevallen gebruik je nu juist WEL class constanten?
of
Code (php)
1
2
2
$kernel->handle($request, HttpKernelInterface::MASTER_REQUEST); // main
$kernel->handle($request, HttpKernelInterface::SUB_REQUEST); // sub
$kernel->handle($request, HttpKernelInterface::SUB_REQUEST); // sub
In zo'n geval geeft een constante een stuk meer leesbaarheid
Code (php)
Versus
Code (php)
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
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
<?php
class Magic {
// even te lui om hier constate te schrijven :p
public function alakazam($mode = 0) {
switch($magic) {
case Sience::COS:
...
break;
case Sience::TAN:
...
break;
case Sience::SIN:
...
break;
case Sience::ACOS:
...
break;
case Sience::ATAN:
...
break;
case Sience::ASIN:
...
break;
}
}
$science = new Sience;
$science->calculate(Science::TAN); // Ok, ik heb een idee wat dit doet.
}
?>
class Magic {
// even te lui om hier constate te schrijven :p
public function alakazam($mode = 0) {
switch($magic) {
case Sience::COS:
...
break;
case Sience::TAN:
...
break;
case Sience::SIN:
...
break;
case Sience::ACOS:
...
break;
case Sience::ATAN:
...
break;
case Sience::ASIN:
...
break;
}
}
$science = new Sience;
$science->calculate(Science::TAN); // Ok, ik heb een idee wat dit doet.
}
?>
En dan zijn er nog use cases zoals versie nummers en codenames die gebruikt zouden kunnen worden om te bepalen of die versie van de software een feature wel ondersteund, of dat er een workaround voor een bug nodig is.
En bijvoorbeeld de constante Request::POST = 'POST', Request::GET = 'GET', Request::PUT = 'PUT', Request::UPDATE = 'UPDATE' wanneer je een om aan (new Request)->setMethod() mee te geven. Dan weet je al behoorlijk zeker dat methode Request::setMethod() die method ook echt ondersteund. Want als dat niet het geval is krijg je een melding dat die constante niet bestaat.
Gewijzigd op 14/10/2013 16:47:02 door Dos Moonen
@Dos: ah ja, die methode ken ik :)
Maar in general, gebruik je constanten alleen wanneer die van buitenaf moeten kunnen worden aangeroepen? Gebruik je een constante nooit enkel en alleen in de class zelf?
http://kohanaframework.org/3.3/guide-api/Route is een voorbeeld. Route::REGEX_SEGMENT is nog te gebruiken (al is dat de default, dus ik zou niet weten waarom) bij het aanmaken van een route, maar de andere twee zal ik nooit nodig hebben.
Dat komt inderdaad het meeste voor, ja. Maar het komt wel voor, Allright, thanks.