[PHP] Wat vinden jullie van Singletons

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Maghiel
  • Registratie: Maart 2004
  • Laatst online: 20:22
Ik weet dat in PHP singletons niet echt singletons zijn. Maar ik vraag me af wat jullie van singletons vinden? (en dan vooral gericht op de situatie als in php).

Bijvoorbeeld;
Ik gebruik caching, dit en dat, hiervoor heb ik een Cache object en dit en dat.
Ik heb hiervan een singleton gemaakt, want meerdere instanties van Cache per request is toch een verspilling van resources, en is ook niet nodig, vind ik. En aangezien ik als php-er toch enkel te maken heb met aparte requests.. :p

Wat vinden jullie van deze keuze?

Acties:
  • 0 Henk 'm!

  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 20:56
"Ik weet dat in PHP singletons niet echt singletons zijn."

ik zou niet weten waarom PHP singletons geen echte singletons zijn, maargoed. Singleton is een design pattern, en daarmee eigenlijk niet taal-afhankelijk. Daarom kan 't gebruik van Singleton ook in PHP heel effectief zijn.

Of het nou slim is om van je cache object een singleton te maken hangt van je situatie af. Als je zeker wil dat je maar 1 cache object hebt in je applicatie, is het inderdaad waarschijnlijk een goede keus.

Ik heb bijvoorbeeld meerdere cache objecten omdat sommige dingen maar een paar minuten gecached hoeven te worden, en anderen 8 uur lang gecached mogen worden. Ook dan kan je (een soort van) singleton gebruiken door bijvoorbeeld iets te doen als CacheObject::getInstance('longLastingCache')

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


Acties:
  • 0 Henk 'm!

  • Maghiel
  • Registratie: Maart 2004
  • Laatst online: 20:22
freakingme schreef op dinsdag 04 augustus 2009 @ 04:12:
"Ik weet dat in PHP singletons niet echt singletons zijn."

ik zou niet weten waarom PHP singletons geen echte singletons zijn, maargoed. Singleton is een design pattern, en daarmee eigenlijk niet taal-afhankelijk. Daarom kan 't gebruik van Singleton ook in PHP heel effectief zijn.

Of het nou slim is om van je cache object een singleton te maken hangt van je situatie af. Als je zeker wil dat je maar 1 cache object hebt in je applicatie, is het inderdaad waarschijnlijk een goede keus.

Ik heb bijvoorbeeld meerdere cache objecten omdat sommige dingen maar een paar minuten gecached hoeven te worden, en anderen 8 uur lang gecached mogen worden. Ook dan kan je (een soort van) singleton gebruiken door bijvoorbeeld iets te doen als CacheObject::getInstance('longLastingCache')
In PHP zijn singeletons geen echte singletons omdat je enkel te maken hebt met individuele requests.

Waarom ik deze vraag stel is omdat ik veel lees dat mensen een singleton pattern als een anti-pattern beschouwen.

Ik vind je voorbeeld mooi, maar dan maak je dus alsnog meerdere instanties per request. Wat ik zelf doe is bij het aanmaken van een cache al een tijd te geven waarin ie moet verdwijnen. Bij een update/delete etc replace ik het betreffende cache item.

Acties:
  • 0 Henk 'm!

  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 20:56
"In PHP zijn singeletons geen echte singletons omdat je enkel te maken hebt met individuele requests."

Ja, en? :D
Als ik een willekeurige C/C++/Java app heb die singletons gebruikt, zal er bij het opnieuw opstarten van die app opnieuw die singleton objecten geinstantieerd worden. Dit is bij php net zo, alleen draait de gemiddelde php applicatie wat korter (in webomgevingen).

"Some consider it an anti-pattern, judging that it is overused, introduces unnecessary limitations in situations where a sole instance of a class is not actually required, and introduces global state into an application" (Bron)

Heeft wikipedia helemaal gelijk in. Ja; het wordt overused. ja; het brengt limitaties met zich mee. Ja; het introduceert een global. So what?! Imho betekent dat helemaal niet dat Singleton daarmee slecht is, of dat je dat beter niet moet gebruiken. Het enige wat het betekent is (denk ik) dat je er bewust mee om moet gaan, en altijd zal moeten overwegen om een normale instantie te gebruiken.

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

freakingme schreef op dinsdag 04 augustus 2009 @ 05:09:
Heeft wikipedia helemaal gelijk in. Ja; het wordt overused. ja; het brengt limitaties met zich mee. Ja; het introduceert een global. So what?! Imho betekent dat helemaal niet dat Singleton daarmee slecht is, of dat je dat beter niet moet gebruiken. Het enige wat het betekent is (denk ik) dat je er bewust mee om moet gaan, en altijd zal moeten overwegen om een normale instantie te gebruiken.
Ehm, singletons gebruiken bespaard juist het gebruik van een global, althans in de meeste talen dan. Dat is namelijk juist een reden om een singleton te gebruiken. Want als je altijd slechts 1 instantie nodig hebt van een bepaald object in dan is het handiger om daar een singleton voor te gebruiken dan dat je het object in een global zet, puur en alleen maar om je global namespace schoon te houden. Echter je moet natuurlijk daar ook niet in doorslaan, indien het ooit mogelijk is dat je meerdere instanties nodig zou kunnen hebben dan kan je immers niet kiezen voor singleton en wel globals gebruiken. (of je maakt het "ingewikkelder" door een subclass te maken die een singleton is van het hoofdobject, maar dat is rommelen in de marge vind ik).

Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Wat Machiel probeert aan te geven is dat bij JSP en .NET singletons leven zoals de web applicatie leeft. In PHP worden resources niet tussen requests gedeeld en daarom is de levensduur vele malen korter. Er zijn verschillende redenen om singletons te gebruiken en een daarvan kan een langere initialisatie zijn. Als je dan die initialisatie bij elk request krijgt heeft de singleton geen enkele toegevoegde waarde ten opzichte van een class constructor.

Singletons zijn mits goed toegepast zeer nuttig. Singletons worden als een anti-pattern gezien omdat unit testing een stuk lastiger wordt. Zelf heb ik in al mijn (web en desktop) applicaties maar 1 of 2 singletons, en de meest gebruikte initialiseert een IoC adapter.

Overigens kun je voor cache beter een system als Memcache gebruiken en volgens mij is (was) daar standaard ondersteuning voor in PHP. Maar het is ook mogelijk dat deze inmiddels is verplaatst naar de picl repository.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Niemand_Anders schreef op dinsdag 04 augustus 2009 @ 09:13:
Wat Machiel probeert aan te geven is dat bij JSP en .NET singletons leven zoals de web applicatie leeft. In PHP worden resources niet tussen requests gedeeld en daarom is de levensduur vele malen korter. Er zijn verschillende redenen om singletons te gebruiken en een daarvan kan een langere initialisatie zijn. Als je dan die initialisatie bij elk request krijgt heeft de singleton geen enkele toegevoegde waarde ten opzichte van een class constructor.
Wat let je om je singleton class in $_SESSION te gooien? Eventuele database connecties kan je dmv __wake etc restoren. En volgens mij vergeet je het nut van een singleton, dat is niet dat het object bewaard blijft over een paar requests heen, maar dat je eenvoudig die instantie kan aanroepen zonder steeds een nieuw object aan te maken.
Overigens kun je voor cache beter een system als Memcache gebruiken en volgens mij is (was) daar standaard ondersteuning voor in PHP. Maar het is ook mogelijk dat deze inmiddels is verplaatst naar de picl repository.
Uiteraard, maar het is ook handig om een wrapper te maken om de memcache functies van PHP, welke je weer mooi in een singleton kan stoppen :)

Acties:
  • 0 Henk 'm!

  • TheNameless
  • Registratie: September 2001
  • Laatst online: 07-02 21:38

TheNameless

Jazzballet is vet!

Het ligt wat mij betreft aan de omvang van de applicatie wat je aan het maken bent.
Bij kleine projecten die snel af moeten zijn, vind ik het prima om een singleton te gebruiken als je zo een-twee-drie geen andere oplossing kunt bedenken die ook kan werken en die niet veel tijd kost om te maken.

Ik ben zelf op dit moment bezig met een redelijk groot web project in ASP.NET MVC (ben er al een half jaar mee bezig). Ik gebruik hierbij een IoC container en daarmee kan ik problemen oplossing waar ik anders een singleton voor zou gebruiken (configuratie klasse bijvoorbeeld)

Ducati: making mechanics out of riders since 1946


Acties:
  • 0 Henk 'm!

  • Peter
  • Registratie: Januari 2005
  • Laatst online: 13-09 17:10
Het grote probleem met Singleton is dat een object écht maar één keer mag bestaan, ook in geval van bijvoorbeeld Database klasses is dit vaak niet wat je wilt. In een multi-request systeem wat ik ontwikkeld heb gebruik ik Singleton enkel voor de Kernel classes welke o.a. error- en exceptie afhandeling en sessies/cache regelt (op basis van APC of memcached).

Zelf gebruik ik de Dependency Injection methodiek. Dit heeft als voordeel dat het marginaal sneller is (je bespaart een call naar een getInstance static), in principe alles kan wat Singleton ook kan maar je niet limiteerd op juist die instantie.

Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Ik heb alleen ervaring met IoC frameworks op het .NET framework, maar puur IoC is niet handig als je support wilt hebben voor meerdere soorten IoC/DI frameworks en dan gaat het vooral om de zogenaamde annotated DI frameworks zoals Unity, ObjectBuilder of Ninject. Deze hebben elk hun eigen attributen (InjectionConstructor vs Inject attribute). Nu kun je natuurlijk de attributen van beide frameworks toepassen, maar dan is je code weer strongly tied aan bepaalde IoC frameworks en bij een installatie moet je dan ook al die frameworks meeleveren.

Unity en Ninject hebben dan weer wel als voordeel dan de configuratie een stuk minder gevoelig is, omdat hun configuratie in de code gebeurt en je dus code completion en een compiler error krijgt als je een type verkeerd schrijft. Andere frameworks (Windsor containers, Spring, AutoFac, StructureMap, etc) gebruiken een XML configuratie bestand. Windsor 2.0 heeft inmiddels van Ayende Rahien ook als een fluent configuration syntax (Component.For<>().ImplementedBy<>() ) gekregen.

Hoewel Microsoft al zelf met een CSL (Common Service Locator) is gekomen mist deze nog wel een aantal features zoals de mogelijkheid om een bestaande instantie door de CSL te halen (denk bijvoorbeeld aan een HttpApplication instance in je global.asax.cs).

De CSL kan als Singleton gebruikt worden (ServiceLocator.Current) of kan worden geinjecteerd. Wij hebben dus een eigen CSL implementatie en die gebruik ik op beide manieren. De Singleton methode is dus handig in je global.asax waar je geen controle hebt over hoe deze wordt aangemaakt.

C#:
1
2
3
4
5
6
7
8
public class Global : HttpApplication
{
  public Global()
  {
    IocFactory ioc = IocFactory.Current;
    ioc.Load(this); //dependencies worden alsnog geladen voor de HttpApplication
  }
}


Maar op andere plaatsen gebruik je de CSL om een nieuwe instantie aan te maken en de DI injecteerd op dat moment als de gewenste dependencies.

Als Singletons goed worden gebruikt maakt deze unit testing ook niet lastiger. Echter ben ik het wel eens met de algemene regel dat je singletons moet vermijden waar mogelijk. Echter koste wat kost geen singleton (durven te) gebruiken is ook weer niet goed.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Erkens schreef op dinsdag 04 augustus 2009 @ 09:05:
[...]

Ehm, singletons gebruiken bespaard juist het gebruik van een global, althans in de meeste talen dan.
Er stond "global state". En een singleton *is* een global, hoe je het ook wendt of keert. Het enige extra wat je erbij krijgt is wat encapsulatie, maar dat is vaak ook wel op een andere manier op te lossen (zoals private static variables in een class, en alle methods zijn public static methods in die class). Op het moment dat je een singleton gaat gebruiken om wat globals weg te werken dan heb je het duidelijk niet begrepen.

Een singleton gebruik je imho pas op het moment dat je (ooit) gebruik maakt (wilt gaan maken) van polymorphisme - je singleton is dan een interface waarmee je praat, en de achterliggende implementatie hangt af van runtime gegevens. Ergo, icm een factory.

[ Voor 17% gewijzigd door .oisyn op 04-08-2009 13:19 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Niet in de reactie waarop ik reageerde ;)
En een singleton *is* een global, hoe je het ook wendt of keert. Het enige extra wat je erbij krijgt is wat encapsulatie, maar dat is vaak ook wel op een andere manier op te lossen (zoals private static variables in een class, en alle methods zijn public static methods in die class). Op het moment dat je een singleton gaat gebruiken om wat globals weg te werken dan heb je het duidelijk niet begrepen.
Ik gebruik een singleton niet om globals weg te werken, maar omdat ik niet overal die singleton nodig heb en het dus niet nuttig is dat ik er direct toegang tot heb.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
function blaat()
{
  global $framework;
  $framework->addContent("blaat");
}

// of

function blaat()
{
  $GLOBALS["framework"]->addContent("blaat");
}


Nee, ik doe het liever zo:
PHP:
1
2
3
4
5
function blaat()
{
  $framework = Framework::getInstance();
  $framework->addContent("blaat");
}


Dan weet ik tenminste zeker dat ik te maken heb met dat Framework object.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Erkens schreef op dinsdag 04 augustus 2009 @ 13:12:
[...]

Niet in de reactie waarop ik reageerde ;)
Jawel, in de wikipedia quote ;). Ik ga er vanuit dat dat ook is wat freakingme bedoelde.
Ik gebruik een singleton niet om globals weg te werken
Oh ik bedoelde het meer in het algemeen, niet dat jij dat deed :)
maar omdat ik niet overal die singleton nodig heb en het dus niet nuttig is dat ik er direct toegang tot heb.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
function blaat()
{
  global $framework;
  $framework->addContent("blaat");
}

// of

function blaat()
{
  $GLOBALS["framework"]->addContent("blaat");
}


Nee, ik doe het liever zo:
PHP:
1
2
3
4
5
function blaat()
{
  $framework = Framework::getInstance();
  $framework->addContent("blaat");
}
De vraag die je jezelf dan kunt stellen is: waarom niet gewoon Framework::addContent()?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

.oisyn schreef op dinsdag 04 augustus 2009 @ 13:21:
De vraag die je jezelf dan kunt stellen is: waarom niet gewoon Framework::addContent()?
Natuurlijk kan dat, alleen dan moet je alles static gaan maken en dat werkt minder lekker vooral met overerving etc :)

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Overerving is een belangrijk punt idd. Had ik ook in mijn eigen reactie erbij geedit, wellicht dat je die gemist hebt (het gaat ook allemaal een beetje langzaam hier @ campzone ;))
.oisyn schreef op dinsdag 04 augustus 2009 @ 12:59:
Een singleton gebruik je imho pas op het moment dat je (ooit) gebruik maakt (wilt gaan maken) van polymorphisme - je singleton is dan een interface waarmee je praat, en de achterliggende implementatie hangt af van runtime gegevens. Ergo, icm een factory.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

.oisyn schreef op dinsdag 04 augustus 2009 @ 13:36:
Overerving is een belangrijk punt idd. Had ik ook in mijn eigen reactie erbij geedit, wellicht dat je die gemist hebt (het gaat ook allemaal een beetje langzaam hier @ campzone ;))

[...]
Dat had ik idd gemist :)

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Mja, de keuze tussen 'singleton' en IoC is wat mij betreft altijd ten faveure van IoC. Bij 'singleton' heeft klasse X zélf de verantwoordelijkheid om een instantie van,. bijvoorbeeld, een databaseverbinding te krijgen. Bij IoC wordt die verantwoordelijkheid uit die klasse gehaald. Hierdoor wordt de klasse eenvoudiger, heeft minder verantwoordelijkheid, en daardoor is er minder code, minder kans op fouten, (veel) eenvoudiger om te testen, enzovoort. Ik bedoel, als je een unit test voor een class met een singleton wilt maken, moet je eerst in je unit test die singleton gaan vervangen - wat nogal moeilijk gaat. Met IoC kun je simpelweg je object instantieren met een aantal mock objects, en zo je tests veel en veel eenvoudiger houden.

En met singleton heb je ook altijd nog de vraag - welke classes gebruiken mijn singleton nu? En daarmee ook: Nee, ik moet deze singleton niet aanpassen, want ik weet niet wie het allemaal gebruiken. Daar zijn wel truukjes voor misschien, maar IoC is mijns insziens wel een stuk eenvoudiger in onderhoud en vooral flexibiliteit.

En dat zijn, ook weer mijns insziens, de belangrijkste criteria voor een goed ontworpen OO project - flexibiliteit, eenvoud, etcetera.

/rant

Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

YopY schreef op dinsdag 04 augustus 2009 @ 13:56:
En met singleton heb je ook altijd nog de vraag - welke classes gebruiken mijn singleton nu? En daarmee ook: Nee, ik moet deze singleton niet aanpassen, want ik weet niet wie het allemaal gebruiken. Daar zijn wel truukjes voor misschien, maar IoC is mijns insziens wel een stuk eenvoudiger in onderhoud en vooral flexibiliteit.
Als je niet weet welke classes gebruikt worden dan klopt of je code niet of je documentatie is onvoldoende en heb je dus een groter probleem dan het toepassen van een bepaald design pattern.

Jouw voorbeeld van een singleton waarvan je niet weet wat hij "gebruikt" maakt namelijk niks uit of het een singleton is of een normale class in dat geval ;)

Overigens (ik heb nooit IoC gebruikt en haal mijn kennis nu even heel fout van Wikipedia: Inversion of control) lijkt me dat je met IoC veel sneller onoverzichtelijke code krijgt:
There are in the end five classes needed to switch a lamp after pressing a button. In procedural programming this could have been implemented using one method. Inversion of Control has the advantage and power to uncouple implementations from each other, but the orchestration is more complex.
Dat lijkt mij toch tamelijk complex :o
Maar ik zal me eens wat meer in dit design pattern gaan verdiepen als ik wat tijd over hem :)

Acties:
  • 0 Henk 'm!

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Bij het gebruik van een singleton binnen classes maakt je class afhankelijk van deze singleton. Dit kan diep verborgen zijn in de code. Als je een class als black-box beschouwt krijg je dus behaviour wat niet voorzien kan worden vanuit de aanroepende code. Als je al singletons gebruikt is het beter om deze 'dependency' te injecteren in het object bij het aanmaken van het object. Dan kan de classe een singleton gebruiken, maar ook niet (bv handig bij unit-testen). Als je op deze manier werkt, waarbij de dependencies altijd door de aanroepende code zichtbaar zijn of worden aangereikt dan zal je ook zien dat de behoefte aan singletons snel afneemt en je code eleganter wordt. Ik heb het zelf eigenlijk zelden nodig.
Pagina: 1