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:
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:
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.
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...
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