singleton of ... ?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Ivar

ivar

05/01/2009 17:42:00
Quote Anchor link
Hallo,

Ik ben onlangs begonnen met het OO programeren.

Nu heb ik verzonnen dat ik een class 'core' heb die dingen afhandeld als berichtgeving naar de gebruiker, of debug info etc.

om nu gebruik te kunnen maken van de functions in 'core' laat ik iedere andere class 'core' extenden, maar nu komt het: hoe zorg ik er voor dat alle extendende classes dezelfde instantie van 'core' gebruiken zodat alle berichten bij elkaar uitkomen?

ik zat te denken aan singleton, maar ik heb gelezen dat dit meestal niet nodig is en anders toch wel geen idee is ivm beperkingen die dan optreden.

of is er nog een andere (betere) optie?

bij voorbaat alvast denk voor het lezen van m'n vraag

Ivar

PS als je iets niet snapt aan mijn vraag vraag het dan, dan kan ik het uitleggen!
 
PHP hulp

PHP hulp

28/04/2024 22:17:44
 
Midas

Midas

05/01/2009 17:48:00
Quote Anchor link
Zodat alle berichten bij elkaar uit komen?
 
Hipska BE

Hipska BE

05/01/2009 17:55:00
Quote Anchor link
Quote:
hoe zorg ik er voor dat alle extendende classes dezelfde instantie van 'core' gebruiken
Dat is technisch onmogelijk (in gelijk welke taal), een pointer kan maar een instantie van 1 class bevatten.

Tenzij jij zo iets bedoeld:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php

$core
= new Core();

$core1 = new SubCore();
$core1->core = $core;

$core2 = new OtherSubCore();
$core2->core = $core;

?>

Nu zit in $core1 en in $core2 een referentie naar de instantie van de 'hoofdcore'. En wel in $this->core
 
Satsume

Satsume

05/01/2009 18:05:00
Quote Anchor link
Ik maak persoonlijk veel gebruik van een registry waar je je referenties van een object in bewaard ( add() ), kijkt of een object bestaat ( exists() ), of ophaald ( get() ).

De registry is dan een singleton object, en is abstract.

Je kan dus altijd je referenties terug vinden door bijvoorbeeld $oCore = Registry::get('Core') op te vragen.

Combineer deze aanpak met $_SESSION en serialize() en je hebt een vergaarbak van referenties, let wel op dat je niet te veel in je registry gaat zetten natuurlijk ;)

Als je behoefte hebt aan een simpele uitwerking van mij registry roep je maar.
 
Martijn B

Martijn B

05/01/2009 19:19:00
Quote Anchor link
Ik denk dat je een singleton bedoelt.

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
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php

class CCore {

    private $_oUser;

    function
__construct()
    {

        $this->_oUser = new CUser;
        self::instance($this);
    }


    public static function instance( CCore $_oInstanceNew = null )
    {

        static $oInstance = null;

        if( $_oInstanceNew )
        {

            $oInstance = $_oInstanceNew;
            return;
        }


        return $oInstance;
    }
}


class CUser {

    private $_oCore;

    function
__construct()
    {

        $this->_oCore = CCore::instance();
    }
}

?>


Werkt prima.

core kan bij user en user bij core. Er is steeds maar 1 instantie van core.

Zo kun je ook een winkelmand en een product klasse maken (net als user). Klasse winkelmand doet iets met producten. Winkelmand kan in deze constructie gebruikt maken van klasse product en andersom (die alles via core).
Gewijzigd op 01/01/1970 01:00:00 door Martijn B
 
Ivar

ivar

05/01/2009 19:57:00
Quote Anchor link
bedankt voor al deze oplossingen

@midas: idd dat bedoel ik.
@hipska: de oplossing die je aandraagt zou wel eens het makkelijkste/best kunnen zijn.
@satsume: ik weet niet ofdat ik wel een registry wil gebruiken, is dit niet een beetje een 'vieze' methode voor dit soort dingen?
@Martijn!: ik bedoelde in eerste instantie idd singleton, maar ik ga nu als eerste eerst de optie van hipska bekijken en eventueel daarna die van jou.
 
Martijn B

Martijn B

05/01/2009 20:09:00
Quote Anchor link
De oplossing van Hipska is ongeveer dezelfde als die van mij.
Er is wel een verschil, in mijn oplossing kun je overal gebruik maken van de core.
 
Satsume

Satsume

06/01/2009 10:10:00
Quote Anchor link
ivar schreef op 05.01.2009 19:57:
bedankt voor al deze oplossingen

@satsume: ik weet niet ofdat ik wel een registry wil gebruiken, is dit niet een beetje een 'vieze' methode voor dit soort dingen?


Absoluut niet, als je al je instanties en aanroepingen daarvan aan de registry overlaat heb je praktisch het zelfde als een singleton, alleen kijkt de registry of er al een instantie van een object bestaat en niet het object zelf. Sterker nog ben ik van mening dat niet alle (als je er meer hebt waar ik donder op zeg/ga zeggen) objecten de functies moeten bevatten om zich als singleton te gedragen, dat is naar mijn mening niet hun plaats.
Een registry vangt dit op door zelf te kijken of er al een instantie van een object bestaat en die eventueel te retourneren, waar jij denkt dat je een nieuwe maakt, overigens als je wel een nieuwe instantie nodig hebt van een oibject kan je natuurlijk forcen of een andere naam mee geven voor dit object.
 
Ivar

ivar

06/01/2009 19:13:00
Quote Anchor link
@satsume, je zei dat je nog wel een klein voorbeeld kon geven van je registry class. ik zou deze graag even zien, omdat ik even wil kijken of dat het echt zoveel simpeler is als dat je zegt (er zal vast een kern van waarheid in zitten).

zou je ook nog andere voorbeelden kunnen geven waarvoor ik dat registry dan zou kunnen gebruiken?
 
Jelmer -

Jelmer -

06/01/2009 20:52:00
Quote Anchor link
Een registery is eigenlijk een soort global scope, maar dan eentje die je wat beter kan beheren doordat je toegang kan regelen met methods. Je kan het gebruiken voor alle objecten, naja, eigen alles wat wordt gedeeld binnen je hele webapplicatie.

Vaak wordt een registery als een singleton klasse gebouwd, zodat er maar één centraal register is.

Heel heel heel simpel:
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
<?php
class Registery {

    static public function sharedInstance() {
        static $instance;
        return $instance ? $instance : $instance = new self();
    }


    protected $_items = array();

    protected function __construct() {
        // protected puur om singleton af te dwingen
    }

    public function set($key, $value) {
        $this->_items[$key] = $value;
    }


    public function get($key) {
        if(!isset($this->_items[$key])) throw new InvalidArgumentException("Het register bevat niets met de naam $key");

        return $this->_items[$key];
    }
}


class DB {

}


$registery = Registery::sharedInstance();
$registery->set('db', new DB());

// willekeurig stukje code
$db = Registery::sharedInstance()->get('db');
?>


Je kan het nadeel ook al een beetje zien, wanneer je deze code in je klassen gebruikt, hebben die klassen altijd een register nodig, en moet dat register altijd die variabele bevatten. Op deze manier kan je dus niet voor klasse a, die het registery gebruikt, database a pakken en voor klasse b, die datzelfde registery gebruikt database b. Tenzij je je registery gaat aanpassen tussen de calls door.

Nog een nadeel is dat de klassen die je registery gebruiken op deze manier altijd afhankelijk zijn van het beschikbaar zijn van de klasse Registery. In theorie maakt dit je klassen minder herbruikbaar, maar in praktijk valt dit in mijn ervaring wel mee.

Wat ikzelf dan wel weer een nadeel vindt is dat je niet aan de aanroep naar de klasse, of aan de buitenkant, alle methods en hun argumenten bij elkaar, kan zien wat de klasse nu werkelijk precies nodig heeft. De API maakt niet duidelijk dat hij ook nog informatie haalt uit een register.

Het eerste en het laatste is deels op te lossen door het Singleton deel weg te laten, en één registery-instance mee te geven aan de __construct. Dan heb je er al meer controle over, maar dan is ook een groot deel van het nut weg, en of het overgebleven nut dan nog opweegt tegen het niet kunnen zien wat de klasse nodig heeft aan de API (de API beschrijft niet wat de inhoud moet zijn van je registery) is dan nog maar de vraag.

Moet je nu geen singleton of registery gebruiken? Dat is helemaal aan jezelf. Ik zelf probeer ze altijd te vermeiden, en je kan heel goed zonder leven heb ik gemerkt, al zal je altijd een soort context-object nodig hebben, een object dat toegang geeft tot bijvoorbeeld de data uit je model wil je MVC deels implementeren. Maar singleton gebruiken is veel minder denkwerk. Je zou kunnen beargumenteren dat dit tot minder mooie code leidt, maar volgens mij valt dat wel mee. Vooral in het begin is het erg handig, in de zin van een gemakkelijke oplossing voor veel problemen die je tegenkomt bij het programmeren a la OOP. En of de nadelen op jouw en je applicatie van toepassing zijn, ligt helemaal aan je eigen eisen :)
 
Ivar

ivar

08/01/2009 08:14:00
Quote Anchor link
bedankt voor dit antwoord, ik zal er binnenkort naar kijken omdat ik daar nu even weinig tijd voor heb (druk op school :P ).
 
Ivar

ivar

09/01/2009 19:17:00
Quote Anchor link
is er iets op tegen om gewoon dit te doen?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
$_SESSION['Core'] = new Core;
$_SESSION['Core']->function();

het werkt, maar is het ook 'netjes'?
 
Han eev

Han eev

09/01/2009 19:27:00
Quote Anchor link
Het kan wel, maar waarom zoiets opslaan in een sessie?
Zoiets zou ik dan bijna eerder opslaan in een $GLOBALS.

(je moet ff wat dubbelposten verwijderen ;-))
 
TJVB tvb

TJVB tvb

09/01/2009 19:42:00
Quote Anchor link
Een sessie is bedoelt om gegevens tussen de verschillende request van een user te delen niet omzomaar alles op te slaan wat je tijdens een request nodig hebt.

Door keuzes te maken met behulp van de design patterns zoals singleton en registry kun je een nette opzet maken voor je applicatie.
 
Ivar

ivar

09/01/2009 19:44:00
Quote Anchor link
ik zou graag die posts weg hebben maar ik kan deze zelf niet verwijderen.
ik wil hier dan ook gelijk aan toevoegen dat ik dit een zeer vervelende bug vind.

@han dit is hier idd beter geschikt voor.

edit: bedankt voor het verwijderen van de posts
edit 2: ik gebruik nu dit in de 'core' class:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
    public function __construct()
    {
        $GLOBALS[__CLASS__] = $this;
    }

en dan kan ik overal deze class aanroepen dmv:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$GLOBALS['Core']->addMsg('HELLO WORLD');

dit werkt, maar als iemand nog een tip heeft om deze methode te verbeteren hoor ik het graag! ik zou eventueel ook de berichten array in een $GLOBALS kunnen zetten, maar ik denk dat dit handiger is :P
Gewijzigd op 01/01/1970 01:00:00 door ivar
 
Jelmer -

Jelmer -

10/01/2009 10:37:00
Quote Anchor link
Wat je nu doet is eigenlijk singleton implementeren, maar dan op zo'n manier dat het niet echt werkt :)

Probleem 1: Je verbindt $GLOBALS['Core'] onlosmakelijk met die ene klasse. Bij een normale singleton implementatie heb je tenminste nog de vrijheid te kiezen welke klasse je aanroept, en bij een registery heb je nog de vrijheid welk object je onder een bepaalde naam in het registery stopt. Dit is in één applicatie niet zo'n probleem, maar zodra je de code wilt hergebruiken is er een redelijke kans dat dit je in de weg gaat zitten.

Probleem 2: Wanneer je nu een nieuwe instantie van Core aanmaakt, overschrijft hij de oude in $GLOBALS['Core']. Alle berichten die in de oude zaten zijn dan foetsie, tenzij je nog een andere referentie had naar die ene oude instantie. Maar dat zou betekenen dat je meerdere instanties van hetzelfde object hebt, wat weer het voordeel van singleton, of een globale message-passer wegneemt.

Probleem 3: $GLOBALS is vrij te veranderen. Wanneer jij eerst de instantie van Core start, en daarna toevallig in een lusje of ergens anders ogenschijnlijk onschuldig een variabele genaamd $core binnen de global scope gebruikt (en die is groot in PHP) is je Core instantie foetsie. Dat is soms best lastig te debuggen, en je moet je best doen goeie variabele-namen te verzinnen die elkaar niet in de weg zitten. Daarom sla je bij Singleton de instantie op in de klasse zelf, zodat het onmogelijk om vanuit de rest van je code bij deze instantie te komen. De klasse heeft volledige controle. (En dat is goed :) )

Ik kan je aanraden je klassen altijd zo autonoom mogelijk te maken. Van zo min mogelijk andere klassen afhankelijk, het liefst van geen enkele gobale variabele afhankelijk, en als je hem toch afhankelijk wilt maken van andere klassen (wel zo handig in veel gevallen, scheelt dingen dubbel implementeren en dubbel fixen) doe dat dan weer zo veel mogelijk via methods, zodat je niet tijdens het bedenken van de klasse beslist welke andere klassen zijn benodigdheden gaan geven (zoals databases) maar maak een method zodat je de database aan de instantie kan koppelen. Op die manier hoef je pas bij het gebruik van de klasse te beslissen hoe je de database gaat aanleveren.

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
<?php
class Teletubbie {
    
    protected $_database;
    
    public function __construct() {
        /* Nu kan je niet om het gebruik van Database heen */
        $this->_database = new Database();
    }
    
}


class Teletubbie {

    protected $_database;
    
    public function __construct($database) {
        /* Het enige waar je je nu nog zorgen over hoeft te maken is of je
         * $database wel kan wat jij hoopt hij kan. Maar daar kan je
         * Interfaces (op PHPfreakz staat een goed artikel daarover)
         * voor gebruiken. */

        $this->_database = $database;
    }

}


$database = new SuperDuperTurboDatabase(); // véél beter dan de normale Database ;)
$teletubbie = new Teletubbie($database);
?>
 
Ivar

ivar

14/01/2009 17:01:00
Quote Anchor link
@Jelmer de aanpak om (in mijn geval) de Core mee te geven in een variable staat mij wel aan, ik zal deze voorlopig gaan gebruiken.

Bedankt allen!
 



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.