[PHP4] Hoe een singleton te implementeren

Pagina: 1
Acties:
  • 151 views sinds 30-01-2008
  • Reageer

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 20:39
Ik ben bezig met een site in PHP. Voornamelijk om wat bij te leren op dit vlak heb ik er voor gekozen om wat meer object geörienteerd aan de slag te gaan. Hierbij loop ik nu tegen een probleem aan wat ik weliswaar kan oplossen, maar waarbij ik niet precies weet welke oplossing de juiste is.
Waar het om gaat zijn generieke objecten die ik binnen andere classes nodig heb. Een typisch geval is een database klasse. In principe wil ik hiervan maximaal 1 instantie hebben waartegen alle verdere classes/objecten uit het script "praten". Enig zoekwerk levert op dat dit a. een typische singleton is; en dat b. PHP4 niet echt ideaal is om dit patroon te implementeren.

De eerste manier waarop het zou kunnen is het maken van een helper functie. Je maakt een functie die toegang tot de klasse verschaft en roept alleen de functie aan:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
function getDbObject() {
  static $db;
  if (!is_object($db)) {
    $db = new db();
  }
  return &$db;
}

class foo {
  foo() {
    $this->DB = getDbObject();
  }
}

Een tweede optie is om het object gewoon aan te maken in de globale scope (het database-object is sowieso op elke pagina nodig). In een willekeurige andere klasse kun je hem dan benaderen door een referentie op te halen. Met een beetje controleerwerk erbij moet je dan in elke klasse een methode als deze opnemen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class foo() {
  foo() {
    $this->DB = $this->initDB();
  }

  function initDB() {
    //check whether DB class exists and contains the correct methods
    if (!isset($GLOBALS[DB_OBJECT])
        || !is_object($GLOBALS[DB_OBJECT])
        || !method_exists($GLOBALS[DB_OBJECT], 'query')
        || !method_exists($GLOBALS[DB_OBJECT], 'numRows')
        || !method_exists($GLOBALS[DB_OBJECT], 'fetchField') ) {

            exception::throw('program', 'No valid DB object available in class "foo".');
    } else {
        $this->DB = &$GLOBALS[DB_OBJECT];
    }
  }
}

Dit heeft het nadeel dat deze functie wss in veel klassen gaat voorkomen en dus voor grof onderhoud gaat zorgen als er wijzigingen in moeten komen. Bovendien vereist dit dat er al een object in de globale scope bestaat.
Een alternatief zou zijn om de check in de de database klasse zelf te implementeren en deze het globale object laten aanmaken. Met de scope resolution operator kun je dan de instantie opvragen.
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
class db {
//get instance with db::getInstance();
    function &getInstance() {

        if (!isset($GLOBALS[DB_OBJECT])) {

            $GLOBALS[DB_OBJECT] = new db();

        } elseif (is_object($GLOBALS[DB_OBJECT])) {

            $methods = get_class_methods('db');
            foreach ($methods as $method) {
                if (!method_exists($GLOBALS[DB_OBJECT], $method) {
                    exception::throw('program', 'DB object overwritten in global scope');
                }
            }
        } else {
            exception::throw('program', 'DB object overwritten in global scope');
        }
        return $GLOBALS[DB_OBJECT];
    }
}

class foo() {
  foo() {
    $this->DB = $db::getInstance();
  }
}

Mijn persoonlijke voorkeur gaat denk ik naar de laatste uit, ondanks dat je hiermee de globale namespace vervuilt en het risico loopt dat je je database object sloopt. De eerste methode vind je echter het meest als je google'd op "PHP singleton".

Mijn vraag is daarom welke oplossing anderen voor dit "probleem" gebruiken, welke te prefereren valt en eigenlijk vooral waarom...

[ Voor 4% gewijzigd door T-MOB op 28-11-2005 01:22 ]

Regeren is vooruitschuiven


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 15-04 22:07

NMe

Quia Ego Sic Dico.

Mijn persoonlijke voorkeur gaat uit naar de eerste methode. Je tweede methode werkt ook, en waarschijnlijk zelfs prima. Sterker nog, feitelijk doet hij exact hetzelfde als de eerste methode, met het verschil dat bij de tweede methode veel meer checks nodig zijn omdat je nu eenmaal in de globale scope zit te werken. Sowieso komt de eerste methode nog het dichtst in de buurt van een klassieke implementatie van het singleton pattern. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Ik doe het altijd op deze manier:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class db{
  var $username;
  function db($username){
    $this->username = $username;
  }
  function &getInstance($username){
    static $instance;
    if(!$instance){
      $instance = new db($username);
    }
    return $instance;
  }
}

[ Voor 3% gewijzigd door Wolfboy op 28-11-2005 01:17 ]

Blog [Stackoverflow] [LinkedIn]


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 20:39
@NME: De derde werkt trouwens ook (na mijn edit althans ;) ), alleen wordt dan het object pas in de globale scope gezet als het nodig is.
Wolfboy schreef op maandag 28 november 2005 @ 01:17:
Ik doe het altijd op deze manier:
[..]
Darn... Dat had ik zelf ook wel kunnen bedenken 8)7 Maar thanx iig, denk dat dit de schoonste oplossing is :)

Regeren is vooruitschuiven


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 15-04 22:07

NMe

Quia Ego Sic Dico.

T-MOB schreef op maandag 28 november 2005 @ 01:31:
@NME: De derde werkt trouwens ook (na mijn edit althans ;) ), alleen wordt dan het object pas in de globale scope gezet als het nodig is.
Ah, je ziet de opties in je TS als 3 verschillende mogelijkheden? Ik dacht dat je derde codevoorbeeld gewoon een verbeterde uitwerking was van het tweede. Lees dan voor elke keer dat ik de tweede mogelijkheid noemde in mijn vorige post maar de derde mogelijkheid. :P
Darn... Dat had ik zelf ook wel kunnen bedenken 8)7 Maar thanx iig, denk dat dit de schoonste oplossing is :)
Sterker nog, dat heb je toch ook zelf verzonnen gevonden? Wolfboy's oplossing is praktisch hetzelfde als jouw eerste codevoorbeeld, met een paar kleine verschilletjes. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • chris
  • Registratie: September 2001
  • Laatst online: 11-03-2022
Misschien dat je hier ook wat mee kan, er staan nog veel meer Design Patterns in php op die site.

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

-NMe- schreef op maandag 28 november 2005 @ 03:03:
Sterker nog, dat heb je toch ook zelf verzonnen gevonden? Wolfboy's oplossing is praktisch hetzelfde als jouw eerste codevoorbeeld, met een paar kleine verschilletjes. :P
Dat dacht ik ook, maar ik ben toch maar weer naar boven gescrolld en zag toen dat TS' implementatie gewoon van een losse functie getDbObject() uitgaat. Ik (en jij misschien ook), dat bij het doorlezen wellicht dat het gewoon een method van een DB klasse was.

En dat is precies zoals Wolfboy het doet en zoals het hoort ;)

Verwijderd

Zijn php functies dan altijd gesynchroniseerd of worden ze domweg niet multithreaded uitgevoerd?

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
Verwijderd schreef op maandag 28 november 2005 @ 09:40:
Zijn php functies dan altijd gesynchroniseerd of worden ze domweg niet multithreaded uitgevoerd?
dat laatste. anders komt er idd iets meer kijken bij het implementeren van een singleton. hoewel ik eerder 'simpelweg' zou zeggen ipv 'domweg' ;)

[ Voor 9% gewijzigd door Genoil op 28-11-2005 10:19 ]


  • Rhapsody
  • Registratie: Oktober 2002
  • Laatst online: 23:48

Rhapsody

In Metal We Trust

Dit is wel een handige site voor je denk ik: http://www.phppatterns.com/docs/design/singleton_pattern

🇪🇺 pro Europa!


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 15-04 22:07

NMe

Quia Ego Sic Dico.

@Rhapsody: lees de post van chris hierboven eens. ;)
Genoil schreef op maandag 28 november 2005 @ 10:18:
dat laatste. anders komt er idd iets meer kijken bij het implementeren van een singleton. hoewel ik eerder 'simpelweg' zou zeggen ipv 'domweg' ;)
Voor 99,9% van alle applicaties die je met PHP maakt heb je dan ook geen multithreading nodig, dus zo dom is dat inderdaad niet. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Verwijderd

-NMe- schreef op maandag 28 november 2005 @ 10:54:
Voor 99,9% van alle applicaties die je met PHP maakt heb je dan ook geen multithreading nodig, dus zo dom is dat inderdaad niet. :P
Jij bent voor 99,9% wel de koning van de uit de duim gezogen statistieken heh :D

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
Verwijderd schreef op maandag 28 november 2005 @ 10:57:
[...]
Jij bent voor 99,9% wel de koning van de uit de duim gezogen statistieken heh :D
Ik denk dat hij wel gelijk heeft. Maar ik zou eerder 100% zeggen. Als je multithreading nodig hebt in een webapp gebruik je immers geen PHP :)

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 20:39
-NMe- schreef op maandag 28 november 2005 @ 03:03:
Sterker nog, dat heb je toch ook zelf verzonnen gevonden? Wolfboy's oplossing is praktisch hetzelfde als jouw eerste codevoorbeeld, met een paar kleine verschilletjes. :P
Mja, vandaar de darn ;)
Ik had wat verkeerde aannames gedaan over de werking van static variabelen. Ik zou zeggen dat een static var binnen een methode van een object statisch zou moeten zijn voor de instantie. Ergo ik zou verwachten dat de volgende code twee keer 1 zou uitspugen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class foo {

    function foo() {
        static $a;
        $a = (isset($a)) ? $a+1 : 1;
    
        echo $a;
    }
}

echo 'a:';
$a = new foo();
echo ' b:';
$b = new foo();

Het resultaat is echter a:1 b:2.

Gevolg is wel dat je met een getInstance() methode een zelf referentie naar het object waar het deel van uit maakt zou kunnen maken.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/** Don not use this, kills PHP **/
class foo {

    var $instance;

    function foo() {
        $this->instance = $this->getInstance();
    }

    function &getInstance() {
        static $instance;

        if (!isset($instance)) {
            $instance = new foo();
        }

        return $instance;
    }
}

Dit werkt (uiteraard?) niet, PHP sterft met een segfault. Wat ik me dan afvraag is of dit een rariteit van PHP is of dat je elke OO taal op deze manier kan omleggen.

Regeren is vooruitschuiven


Verwijderd

Nou ik wilde eigelijk niet in de discussie verzanden anders krijg ik weer de stempel dat ik alleen maar php onderuit wil halen terwijl ik het me gewoon even afvroeg. Maar dat "100%" nog verder van de waarheid afstaat dan "99,9%" wordt bewezen door het aantal topics waar een cronjob wordt aangeraden. ;)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21-04 01:08

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op maandag 28 november 2005 @ 10:57:
[...]
Jij bent voor 99,9% wel de koning van de uit de duim gezogen statistieken heh :D
Wat is dat nou voor onzin, je snapt zelf ook wel dat PHP geen multithreading ondersteunt én dat de meeste applicaties gewoon webbased prut zijn.

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.


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 15-04 22:07

NMe

Quia Ego Sic Dico.

Genoil schreef op maandag 28 november 2005 @ 11:07:
Ik denk dat hij wel gelijk heeft. Maar ik zou eerder 100% zeggen. Als je multithreading nodig hebt in een webapp gebruik je immers geen PHP :)
Ik ben wel eens een situatie tegengekomen waarin het wel handig geweest was als ik had kunnen multithreaden, maar dat was dus niet mogelijk. Uiteraard is daaromheen te werken waardoor je inderdaad op die 100% uitkomt in de praktijk, maar dat neemt niet weg dat je het in die 0,1% wel handig had gevonden. Nuanceverschil tussen "nodig hebben" en "mogelijk zijn".

@mark platvoet: mijn post had niets van doen met het maken van betrouwbare en meetbare statistiek, ik probeerde slechts een punt te maken. Maar als je het graag wil: vervang dan in mijn vorige post "99,9%" door "het overgrote deel" en je bent er ook.
Verwijderd schreef op maandag 28 november 2005 @ 11:11:
Nou ik wilde eigelijk niet in de discussie verzanden anders krijg ik weer de stempel dat ik alleen maar php onderuit wil halen terwijl ik het me gewoon even afvroeg. Maar dat "100%" nog verder van de waarheid afstaat dan "99,9%" wordt bewezen door het aantal topics waar een cronjob wordt aangeraden. ;)
Je hebt dan wel meerdere PHP-processen naast elkaar lopen, maar geen van die processen kan zomaar met de andere communiceren. Daar zul je een manier met files of iets dergelijks voor moeten implementeren AFAIK, dus ook daar heb je gewoon geen multithreading en klopt die 100% nog steeds. ;)

[ Voor 30% gewijzigd door NMe op 28-11-2005 11:17 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Verwijderd

kleine greep uit een simpele singleton class
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
class CDataContainer
{
    var $_items;

    function CDataContainer()
    {
        $this->_items = array();
    }
    
    
    function & getInstance(){
        // Declare a static variable to hold the object instance
        static $instance; 

        // If the instance is not there, create one
        if(!isset($instance)) { 
            $instance = new CDataContainer(); 
        } 
        return($instance);
    }
    
    function GetAt($name)
    {
        $cdc = &CDataContainer::getInstance();
        if(!isset($cdc->_items[$name]))
            user_error("DataContainer couldn't find: $name", E_USER_ERROR);
        else 
            return $cdc->_items[$name];
    }
}

Verwijderd

-NMe- schreef op maandag 28 november 2005 @ 11:15:
Je hebt dan wel meerdere PHP-processen naast elkaar lopen, maar geen van die processen kan zomaar met de andere communiceren. Daar zul je een manier met files of iets dergelijks voor moeten implementeren AFAIK, dus ook daar heb je gewoon geen multithreading en klopt die 100% nog steeds. ;)
Laat maar, je begrijpt het niet.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21-04 01:08

.oisyn

Moderator Devschuur®

Demotivational Speaker

Grappig hoe elke discussie met jou weer strandt met een reactie zoals die je zojuist geplaatst hebt :). Maar goed, wij zullen ook allemaal wel dom zijn.

En Verwijderd in "Welke taal moet je gebruiken voor naamge...", pot verwijt de ketel ;)

[ Voor 29% gewijzigd door .oisyn op 28-11-2005 11:37 ]

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.


Verwijderd

.oisyn schreef op maandag 28 november 2005 @ 11:33:
Grappig hoe elke discussie met jou weer strandt met een reactie zoals die je zojuist geplaatst hebt :). Maar goed, wij zullen ook allemaal wel dom zijn.
Ik heb 'simpelweg' geen behoefte om de discussie aan te gaan. Dat heb ik hierboven ook al vermeld.

edit:
En oja papa van -Nme-: het was maar een grapje hoor. ik ben zeker vergeten de "dit-is-een-poging-tot-een-grapje" ubb tags eromheen te zetten.

[ Voor 19% gewijzigd door Verwijderd op 28-11-2005 11:43 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21-04 01:08

.oisyn

Moderator Devschuur®

Demotivational Speaker

Euh, sorry hoor, maar dit is een discussieforum. Als je niet in discussie wilt gaan moet je hier gewoonweg niet posten, zo simpel zit dat.

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.


  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 22-04 22:07

Bosmonster

*zucht*

Verwijderd schreef op maandag 28 november 2005 @ 11:39:
[...]

Ik heb 'simpelweg' geen behoefte om de discussie aan te gaan. Dat heb ik hierboven ook al vermeld.
Zijn php functies dan altijd gesynchroniseerd of worden ze domweg niet multithreaded uitgevoerd?
Waarom begin je met je eerste reactie in dit topic dan al met PHP (maar weer eens) 'dom' te noemen? Want in zoveel woorden doe je dat hier. Jij weet ook wel dat van multi-threading geen sprake is namelijk..

Magoed.. uiteindelijk ging het om een Singleton in PHP en dan is wolfboy's oplossing de enige fatsoenlijke imho.

[ Voor 8% gewijzigd door Bosmonster op 28-11-2005 11:45 ]


Verwijderd

.oisyn schreef op maandag 28 november 2005 @ 11:41:
Euh, sorry hoor, maar dit is een discussieforum. Als je niet in discussie wilt gaan moet je hier gewoonweg niet posten, zo simpel zit dat.
Ik had gewoon een vraag, en heb antwoord gekregen. En daar ben ik blij om. Ik snap niet dat je er zo over moet zeiken.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21-04 01:08

.oisyn

Moderator Devschuur®

Demotivational Speaker

[rml]mark platvoet in "[ PHP4] Hoe een singleton te implementere..."[/rml] is geen vraag maar gewoon een domme opmerking waar je reacties op kunt verwachten.

Maar goed, back ontopic.

[ Voor 18% gewijzigd door .oisyn op 28-11-2005 11:47 ]

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.


Verwijderd

Bosmonster schreef op maandag 28 november 2005 @ 11:44:Waarom begin je met je eerste reactie in dit topic dan al met PHP (maar weer eens) 'dom' te noemen? Want in zoveel woorden doe je dat hier. Jij weet ook wel dat van multi-threading geen sprake is namelijk..
Gewoon een slechte woordkeuze, niets bijzonders, simpelweg had beter geweest. En ik weet niet hoe php achter de schermen werkt. Ik weet wel dat in tegenstelling tot cgi het php proces niet voor elke request gestart wordt maar dit door php wordt opgelost. Vandaar dat ik het wilde weten

Verwijderd

.oisyn schreef op maandag 28 november 2005 @ 11:47:
[rml]mark platvoet in "[ PHP4] Hoe een singleton te implementere..."[/rml] is geen vraag maar gewoon een domme opmerking waar je reacties op kunt verwachten.
Maar goed, back ontopic.
Je leest ook gewoon niet heh.
|:(

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21-04 01:08

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op maandag 28 november 2005 @ 11:52:
[...]
Je leest ook gewoon niet heh.
|:(
Of jij schrijft niet wat je nou eigenlijk bedoelt.
Verwijderd schreef op maandag 28 november 2005 @ 11:48:
[...]
Gewoon een slechte woordkeuze, niets bijzonders, simpelweg had beter geweest. En ik weet niet hoe php achter de schermen werkt. Ik weet wel dat in tegenstelling tot cgi het php proces niet voor elke request gestart wordt maar dit door php wordt opgelost. Vandaar dat ik het wilde weten
Daarmee is je script nog niet multithreaded, elk script heeft zijn eigen context. Hoe PHP dat verder implementeert is vanuit het oogpunt van je script niet interessant, je kunt er namelijk niets mee. En ook een cronjob heeft niets met multithreading te maken.

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.


Verwijderd

.oisyn schreef op maandag 28 november 2005 @ 11:58:
Daarmee is je script nog niet multithreaded, elk script heeft zijn eigen context. Hoe PHP dat verder implementeert is vanuit het oogpunt van je script niet interessant, je kunt er namelijk niets mee. En ook een cronjob heeft niets met multithreading te maken.
Precies, vandaar dus de vraag...
Een cronjob voldoet aan de behoefte om taken (getimed) asynchroon met de huidige taak te laten lopen, you do the math ;)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21-04 01:08

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een cronjob wordt idd gebruikt om dingen op tijd te laten lopen, wat met PHP onder een webserver uiteraard niet mogelijk is omdat die pas wordt aangeroepen bij een request van een user. Een cronjob wordt meestal niet gebruikt om scripts asynchroon naast elkaar te laten lopen. Een cronjob is dus zeker geen alternatief voor multithreading, daarvoor zou je gewoon nog een php process kunnen spawnen vanuit je script.

[ Voor 12% gewijzigd door .oisyn op 28-11-2005 12:13 ]

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.


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 20:39
Als jullie zijn uitgekibbeld... :> ;)
Iemand hier nog een idee over?

Regeren is vooruitschuiven


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21-04 01:08

.oisyn

Moderator Devschuur®

Demotivational Speaker

T-MOB schreef op maandag 28 november 2005 @ 11:09:
[...]

Mja, vandaar de darn ;)
Ik had wat verkeerde aannames gedaan over de werking van static variabelen. Ik zou zeggen dat een static var binnen een methode van een object statisch zou moeten zijn voor de instantie. Ergo ik zou verwachten dat de volgende code twee keer 1 zou uitspugen:
Dan vraag ik me af hoe PHP dat gaat implementeren aangezien er geen verschil bestaat tussen static en nonstatic methodes :) Overigens hoef je die hele ifs niet te doen, de intialisatie van een static gebeurt bij de eerste aanroep van de functie. Dit werkt dus ook:

PHP:
1
2
3
4
5
function &GetDB()
{
    static $db = new DB();
    return $db;
}


Dat je code segfault komt omdat je een infinite loop hebt (stom dat PHP daar niet zelf mee komt overigens, ipv gewoon maar te segfaulten) :). Je constructor van foo roept namelijk getInstance() aan. Maar je maakt een nieuwe foo aan voordat je 'm toekent aan de static $instance variabele. Als getInstance dus nog een keer wordt aangeroepen vanuit de constructor van foo, is er nog geen $instance gezet en wordt er weer een nieuwe gemaakt. Dat resulteert uiteraard weer in een constructor die weer getInstance aanroept, ad infinitum :)

[ Voor 24% gewijzigd door .oisyn op 28-11-2005 12:53 ]

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.


  • Eärendil
  • Registratie: Februari 2002
  • Laatst online: 22:45
T-MOB schreef op maandag 28 november 2005 @ 11:09:
[...]
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/** Don not use this, kills PHP **/
class foo {

    var $instance;

    function foo() {
        $this->instance = $this->getInstance();
    }

    function &getInstance() {
        static $instance;

        if (!isset($instance)) {
            $instance = new foo();
        }

        return $instance;
    }
}
Dit zal in veel andere talen ook een stack-overflow opleveren, als de 'static $instance' niet geset is zullen de functies elkaar namelijk oneindig blijven aanroepen zonder te returnen.

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 22-03 18:12
Je zou ook nog kunnen denken aan een simpele controle.
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
<?php

class Singleton
{
    static $instance;
    static $allowConstruction = false;
    
    function &getInstance()
    {
        if ( is_null(self::$instance) )
        {
            self::$allowConstruction = true;
            self::$instance = new Singleton();
            self::$allowConstruction = false;
        }
        return self::$instance;
    }
    
    function Singleton()
    {
        if ( !self::$allowConstruction ) die("You are not allowed to construct a Singleton object! Use Singleton::getInstance() to obtain a reference.");
        
        // constructie
    }
}

?>

Het is overigens niet bedoeld als een waterdichte methode oid. meer om fouten in client code sneller te kunnen opsporen. Maar met goede documentatie van je class hoef je daar ook geen problemen mee te krijgen.

[ Voor 4% gewijzigd door Michali op 28-11-2005 13:15 ]

Noushka's Magnificent Dream | Unity


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 20:39
@.Oisyn, Earendil: Ah, duh. Dat is duidelijk.

@Michali: Dat werkt alleen in PHP5. In 4.3.10 kun je althans geen static vars declareren buiten een functie, dus ook niet direct in je klasse.

Regeren is vooruitschuiven


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 22-03 18:12
Hmm, ok. Ik dacht me nog te kunnen herinneren dat ik php4 wel static class members heb gebruikt.

Noushka's Magnificent Dream | Unity

Pagina: 1