[PHP(5)] Ervaringen met diverse Database Abstraction Layers

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

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Ik gebruik al een tijdje voor al m'n scriptjes een zelfgemaakte klasse die mijn SQL-Queries aan de mysql database aanbied en het resultaat naar mijn scriptje doorsluist.
Nu ga ik binnenkort aan een iets groter hobbyproject beginnen en ik vroeg me af of er layers bestaan die wat beter in elkaar zitten. Beter wil zeggen: Snel en veel akties op
veel databases ondersteunen. Errorafhandeling verzorg ik liever zelf.
Nu heb ik al het één en het ander rond gekeken en mijn oog viel op de volgende dingen.

DBX
Dit is standaard in php te vinden en schijnt snel te zijn. Echter het aantal ondersteude functies valt erg tegen. Ze adviseren zelf ook het niet te gebruiken. :?

DB_Sql
Deze klasse in PHPLib schijnt (althans enkele jaren geleden) door veel mensen gebruikt te worden. Volgens de documentatie heeft het heel wat leuke functies. Echter heb ik geen idee of hij naast MySQL/Oracle nog meer databases ondersteunt en ook de snelheid is onbekend.

DB/MDB
Diverse PEAR modules zeggen ook een database abstraction layer te zijn. Volgens de documentatie ondersteunen ze veel databases maar zijn deze snel en wat bieden ze aan functies?

Mijn vraag was dan ook. Zijn er tweakers die één van deze of andere Database Abstraction Layers gebruiken? Wat zijn dan de ervaringen met deze klassen? Ik hoop dat dat de keuze voor mij en medetweakers een stukje simpeler maakt.
De search levert trouwens wel een aantal topics over de meeste klassen op maar nergens worden ze tegen elkaar afgezet en de topics zijn meestal al vrij bejaard.

Acties:
  • 0 Henk 'm!

  • Skaah
  • Registratie: Juni 2001
  • Laatst online: 16-09 18:38
Ik heb overwogen om een bestaande DBAL te gebruiken, maar uiteindelijk ben ik toch voor mijn eigen gegaan, je hebt dan de features, snelheid en alles zelf in de hand.

Natuurlijk is het langzamer dan native met een database te babbelen, maar de voordelen (caching, insert en update met een array, etc) wegen daar ruimschoots tegen op.

Pear heb ik geprobeerd, maar kreeg ik niet aan de praat. Wat waarschijnlijk aan mijn geringe OOO-kennis van PHP lag.

Mijn DBAL is te vinden op www.codebase.nl (niet nieuwste versie), MySQL en PostgreSQL support (SQLite alpha)

[edit]
Voor wanneer je zelf gaat schrijven:
• Maak een object vanwaaruit je met je back-end babbelt
• Maak ook een object voor resultssets (geen arrays)
• Zorg dat je de alle back-end afhankelijke code in één method stopt
• Werk volgens het KISS principe
• Vergeet niet dat back-end afhankelijkheid een illusie is (Vergelijk: LIMIT 10,15 met LIMIT 10 OFFSET 15)

[ Voor 26% gewijzigd door Skaah op 15-06-2004 17:59 ]


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Ook ik heb een database abstraction layer geschreven omdat de PEAR::DB gewoon veel te log was IMHO (3000 regels voor de mysql class is een beetje veel, zeker als het bij drukke sites iedere keer geparsed moet worden..) ik heb toen in PHP4 eerst een stuk of wat layers geschreven om te 'oefenen' nouja, ze voldeden telkens net niet. Mijn (huidige) PHP5 DBAL vind ik zelf erg clean/netjes. Ik heb mezelf nou ook aangeleerd om voor ieder project een Query-class te schrijven, die netjes de (je raad het al ;)) queries uitvoerd, exceptions afvangt en waar nodig een result-class returned omdat ik mijn kop al een paar keer heb gestoten aan het (simpele doch stomme) feit dat ik de queries rechtstreeks in de DB::Query functie typte.

Voor het schrijven van een eigen DBAL is het handig om om te kijken naar het "(abstract) factory pattern" het "iterator pattern" en design patterns in het algemeen.

Acties:
  • 0 Henk 'm!

  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Zelf schrijven dus :)
Maak ook een object voor resultssets (geen arrays)
Waarom geen arrays? Ik dacht dat objecten juist performaceloss gaven, wat is dan het voordeel van het gebruik van objecten?
Vergeet niet dat back-end afhankelijkheid een illusie is (Vergelijk: LIMIT 10,15 met LIMIT 10 OFFSET 15)
Ik snap niet echt wat hiermee bedoeld wordt... Je bedoeld dat andere databases ook een ander SQL-Dialect kunnen hanteren?

[ Voor 3% gewijzigd door Maxonic op 16-06-2004 00:43 ]


Acties:
  • 0 Henk 'm!

  • Skaah
  • Registratie: Juni 2001
  • Laatst online: 16-09 18:38
Maxonic schreef op 16 juni 2004 @ 00:42:
Zelf schrijven dus :)

[...]

Waarom geen arrays? Ik dacht dat objecten juist performaceloss gaven, wat is dan het voordeel van het gebruik van objecten?
In arrays kun je alleen het resultaat opslaan, als je metadata wilt opslaan (zoals het aantal rijen, de veldnamen of -types) kun je een object makkelijker veranderen (methods en properties eenvoudig toevoegen). Een array kan wel, maar ik ben er zelf tegenaan gelopen dat het niet het handigst is. Wanneer je in een later aspect iets wilt veranderen aan je resultssets, kun je veel beter backwards compatibility behouden, IMHO.

Performance moet je wel in het achterhoofd houden, maar is in principe niet het doel. (Het doel is: een goede applicatie schrijven).
[...]

Ik snap niet echt wat hiermee bedoeld wordt... Je bedoeld dat andere databases ook een ander SQL-Dialect kunnen hanteren?
Ja. MySQL kent een LIMIT $offset,$aantal statement, PostgreSQL kent een LIMIT $aantal OFFSET $offset en MSSQL werkt met een dubbele TOP constructie. Zo zjin er wel meer dingen die per back-end anders geregeld zijn.

Acties:
  • 0 Henk 'm!

  • Gert
  • Registratie: Juni 1999
  • Laatst online: 07-11-2024
Daarom moet je je query ook in stukjes opbouwen en dan uiteindelijk voor het gebruikte dialect de stukjes aan elkaar plakken.

Acties:
  • 0 Henk 'm!

  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Gert schreef op 16 juni 2004 @ 12:13:
Daarom moet je je query ook in stukjes opbouwen en dan uiteindelijk voor het gebruikte dialect de stukjes aan elkaar plakken.
Ja, dat is wel een goed idee.
Op die manier zou je dus je scripts ook met databases die je met relationele algebra moet benaderen kunnen laten werken. Kwestie van die layer aanpassen.

Ik zou dus 3 klassen kunnen maken.
- 1 Abstracte klasse waarin alle gemeenschappelijke functies worden vastgelegd en indien mogelijk gevuld.
- 1 Klasse (per db) die de abstracte klasse extend en waarin alle database specifieke functies worden gevuld. Connecten, Query, Fetch_Object, enz.
- 1 Klasse (per db) die de klasse voor de db hierboven extend en waarin functies staan om queries op te bouwen. Limit, Update, Count, enz.

En nog iets...
Nu zie ik in sommige DBALs ook dat mensen een stack maken waarin ze de results kunnen pushen en poppen. Heeft dit behalve dat het leuk ( :9~ ) is nog iets van nut?

Acties:
  • 0 Henk 'm!

  • Macros
  • Registratie: Februari 2000
  • Laatst online: 15-05 16:29

Macros

I'm watching...

Pushen en poppen is altijd leuk ;)
Maar het grote voordeel van een stack is dat je 2 super simpele methodes hebt beide zonder speciale argumenten, waardoor het erg elegant is.

Ik had een tijd geleden samen met iemand anders een CMS geschreven voor MySQL. Later wilde we die aanpassen voor een Oracle database. We hadden al een database classe voor MySQL. Die slikte gewone SQL queries dus was niet veel meer dan een wrapper en wat extra feautures. We hoopten vooral dat SQL tussen beide databases bijna gelijk zou zijn, wat jammer genoeg niet zo was.
Uiteindelijk is er een methode geschreven die MySQL dialect omzette naar Oracle dialect. Was best ranzig, maar werkte meestal wel ;)

[ Voor 60% gewijzigd door Macros op 16-06-2004 13:48 ]

"Beauty is the ultimate defence against complexity." David Gelernter


Acties:
  • 0 Henk 'm!

  • bat266
  • Registratie: Februari 2004
  • Laatst online: 24-08 06:41
Macros schreef op 16 juni 2004 @ 13:46:
Pushen en poppen is altijd leuk ;)
Maar het grote voordeel van een stack is dat je 2 super simpele methodes hebt beide zonder speciale argumenten, waardoor het erg elegant is.

Ik had een tijd geleden samen met iemand anders een CMS geschreven voor MySQL. Later wilde we die aanpassen voor een Oracle database. We hadden al een database classe voor MySQL. Die slikte gewone SQL queries dus was niet veel meer dan een wrapper en wat extra feautures. We hoopten vooral dat SQL tussen beide databases bijna gelijk zou zijn, wat jammer genoeg niet zo was.
Uiteindelijk is er een methode geschreven die MySQL dialect omzette naar Oracle dialect. Was best ranzig, maar werkte meestal wel ;)
maar ik zie het voordeel van die stack nog niet zal wel aan mij liggen :X
idd best een ranzige methode om sql dialecten om te toveren ;)

[ Voor 4% gewijzigd door bat266 op 16-06-2004 13:50 ]

Better to remain silent and be thought a fool then to speak out and remove all doubt.


Acties:
  • 0 Henk 'm!

  • Skaah
  • Registratie: Juni 2001
  • Laatst online: 16-09 18:38
Maxonic schreef op 16 juni 2004 @ 13:29:
[...]


Ja, dat is wel een goed idee.
Op die manier zou je dus je scripts ook met databases die je met relationele algebra moet benaderen kunnen laten werken. Kwestie van die layer aanpassen.

Ik zou dus 3 klassen kunnen maken.
- 1 Abstracte klasse waarin alle gemeenschappelijke functies worden vastgelegd en indien mogelijk gevuld.
- 1 Klasse (per db) die de abstracte klasse extend en waarin alle database specifieke functies worden gevuld. Connecten, Query, Fetch_Object, enz.
- 1 Klasse (per db) die de klasse voor de db hierboven extend en waarin functies staan om queries op te bouwen. Limit, Update, Count, enz.
Je zou ook je query als object kunnen maken, en dat passen naar je database object.

Je krijgt dan
• Een object met de gemeenschappelijke functies voor MySQL en PostgreSQL (met bijvoorbeeld UPDATE en DELETE functies)
• Een object per back-end dat het eerste object overschrijft (met bijvoorbeeld geoptimaliseerde functies voor MySQL.
• Een object dat een query voorstelt en geinterpreteerd wordt door het tweede object.
• Een object voor de resultsets.
En nog iets...
Nu zie ik in sommige DBALs ook dat mensen een stack maken waarin ze de results kunnen pushen en poppen. Heeft dit behalve dat het leuk ( :9~ ) is nog iets van nut?
Een stack is een soort primitieve array.

Acties:
  • 0 Henk 'm!

  • bat266
  • Registratie: Februari 2004
  • Laatst online: 24-08 06:41
Skaah schreef op 16 juni 2004 @ 16:19:

[...]

Een stack is een soort primitieve array.
maar wat is ier nu het grote voordeel van aangezien ik t nog steeds niet zie

Better to remain silent and be thought a fool then to speak out and remove all doubt.


Acties:
  • 0 Henk 'm!

  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Even ter controle dat ik begrijp wat de mensen hier proberen uit te leggen:
Ik heb nu een scriptje geschreven, sorry voor de lap code:

class.db.php
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
abstract class DBParent
{
    // Verbindingsgegevens
    protected var $host; // Database Host: Standaard 'localhost'
    protected var $user; // Database User
    protected var $pass; // Database Password
    protected var $port; // Database connectie poort
    protected var $dbName; // Naam van de Database
        
    // Overige gegevens
    protected var $reqType // Vereistte Database Klasse
    protected var $thisType; // Gelade Database Klasse: (mysql, odbc, pgsql, mssql, fbsql, sybase_ct, oci8, sqlite) 
    protected var $persistent; // Persistente verbinding 0/1
    protected var $link; // Datalink object
    protected var $dbSelected = false; // Boolean
    protected var $queryNum = 0; // Aantal uitgevoerde queries door de instatie 'link'
    protected var $result = array(); // Stack met query results 
     
    // Explode de url en controleer op juiste database type
    function __construct($url, $persistent) 
    {  
        preg_match("!(\w+):\/\/([0-9a-z_]+):?(.*?)@(.*?):?(\d*)\/(\w+)!si", $connection, $matches);
        $this->type       = strtolower($matches[1]);
        $this->user       = $matches[2];
        $this->pass       = $matches[3];
        $this->host       = $matches[4];
        $this->port       = $matches[5];
        $this->dbName     = $matches[6]; 
        $this->persistent = $persistent;
              
        if ($this->reqType == $this->thisType) {
            $this->connect();   
        } else {
            ## throw mismatch error
        }  
    }  
    
    // Bij destruct van het object, niet persistente verbinding sluiten
    function __destruct()
    {
        if (!$this->persistent){
            $this->close();
        }
    }   
    
    // Bij printen object: het type en de verbindingsstatus weergeven
    function __toString() 
    { 
        return $this->thisType.($this->isConnected() ? ' Connected' : ' Not Connected');
    }
    
    // Returned Boolean of er een verbinding is en een database open is 
    public function isConnected()
    {
        return ($this->dbSelected && $this->link);    
    }
    
    # Dit zit me nog niet lekker 
    public function push($sql)
    {
        array_push($result, new Result($this->link, $sql));
        $this->queryNum++; // Verhoog de query tellen
    }
    
    # Dit zit me nog niet lekker 
    public function pop()
    {
        return array_pop($result); // Laatste result
    }
    
    // Abstracte functies: (minimaal vereist in childs)
    abstract function connect();
    abstract function close();
    abstract function switch_db();
    abstract function insert_id();
}
?>


class.mysql.db.php (Dit kan dus een ander bestand zijn voor een andere db)
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?php
// Importeer de parent
require_once('class.db.php');

public class MySQL extends DBParent // Database specifieke functies
{
    function __construct($url='mysql://root@localhost:3306/db', $persistent=0) 
    { 
        $this->thisType = 'mysql'; // Set het type database dat deze klasse aankan
        parent::__construct($url,$persistent); // Roep de constructor van de parent aan
    }
    
    // Verbind met de MySQL Database
    public function connect() 
    {  
        $server = $this->port ? $this->host.':'.$this->port : $this->host; // Als er een poort opgegeven is deze aan de hostname toevoegen
         
        if ($this->persistent){
            $this->link = mysql_pconnect($server, $this->user, $this->pass);
        } else {
            $this->link = mysql_connect($server, $this->user, $this->pass);
        }
        
        $this->dbSelected = mysql_select_db($this->dbName);
    }  
    
    // Sluit verbinding met de MySQL Database
    public function close()
    {
        mysql_close($this->link);
    }
    
    // Open een andere database
    public function switch_db($dbName)
    {  
        $this->dbName = $dbName;
        $this->dbSelected = mysql_select_db($this->dbName);  
    }  
    
    // Geef het id dat gegenereerd werd door de vorige INSERT query
    public function insert_id()
    {
        return mysql_insert_id();
    }
}

public class Database extends MySQL // Database specifieke functies voor SQL opbouw
{         
    private var $sql;
    
    // Voer de opgebouwde query uit 
    public function flush_sql()
    {
        $this->result = $this->push($this->sql);
    }
    
    // Begin de opbouw opniew zonder de vorige query uit te voeren  
    public function reset_sql()
    {
        unset($this->sql);
    }

    // Specificeer welke velden uit welke tabel je wilt selecteren
    public function select($tabel, $fields='*')
    {
        $this->sql .= 'SELECT '.$fields.' FROM '.$tabel;
    }
    
    // Bouw een WHERE clausule
    public function where(array $conditions) // Parameter $conditions: Keys zijn velden, Values zijn condities
    {
        $this->sql .= ' WHERE';
        while (list($key,$val) = each($conditions))
        {
            $this->sql .= ' '.$key.'=\''.$val.'\'';
        }
    }
    
    // Geef een LIMIT aan de SQL-query
    public function limit($begin, $end)
    {
        $this->sql .= ' LIMIT '.$begin.','.$end;
    }
} 

public class Result // Uitgevoerde queries en functies op die query
{         
    private var $sql;
    private var $query;
    
    public var $field; // Object met resultaten
    
    function __construct($link, $sql) // Voer bij intialisatie de query uit
        $this->sql = $sql;
        $this->query = mysql_query($link, $sql);    
    }
    
    function __destruct() // Geef geheugen vrij bij destruction van de query
    {  
        mysql_free_result($this->query);  
    } 
    
    # Dit zit me nog niet zo lekker 
    // Haal de waarden van de gevonden velden op 
    public function fetch()
    {
        return $this->field = fetch_object($this->query);
    }

    public function result($row)
    {
        return mysql_result($this->query, $row);
    }

    public function num_rows()
    {
        return mysql_num_rows($this->query);
    }
} 
?>


toepassing.php Een voorbeeldje van toepassing
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?
require_once('class.mysql.db.php');
$db = new Database('mysql://user:pass@localhost:3306/schoenendb',0);
$db->select('Schoenen', 'merk, type');
$db->where(array('kleur' => 'zwart', 'maat' => '42'));
$db->flush_sql();

echo 'Lijst zwarte schoenen met maat 42:<br>'
while($schoen = $db->pop()->fetch())
{
    echo $schoen->merk.' ('.$schoen->type.')<br>';
}
?>


Uitraard mis ik het één en ander aan functies en er zullen ook syntax fouten in zitten, maar dit is in ieder geval hoe ik het in mij hoofd had en hoe ik het even snel in elkaar gedraaid heb.
Nu denk ik zelf dat dit makkelijker kan. Ik zie alleen niet de logica in van waar ik het verkeerd doe. Is dit zoals jullie bedoelen of ben ik van een andere wereld? ;)

[ Voor 19% gewijzigd door Maxonic op 16-06-2004 18:43 ]


Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

[somewhat offtopic]
Skaah:
Een stack is een soort primitieve array.
:?

Een stack is een type dataset. De karakteristiek van een stack zit hem in het feit dat je volgens een lifo principe data erin stopt en eruit haalt; i.e. last in, first out (resp. push en pop). Het woord "stack" betekent "stapel", wat er op wijst dat het niet geschikt is om iets van "onderaf de stapel" te trekken, maar om gegevens bovenop te stapelen (pushen) en er weer af te halen (poppen).

Voorbeeldje:
PHP:
1
2
3
4
5
6
7
8
$stack = array ();

array_push ( $stack, 'a' );
array_push ( $stack, 'b' );
array_push ( $stack, 'c' );
while ( count ( $stack ) ) {
   printf ( "%s\n", array_pop ( $stack ) );
}

uitvoer:
c
b
a
In PHP is het dan gebruikelijk om een array te gebruiken om je data in op te slaan, maar dat is helemaal geen vereiste voor het principe van een stack.

Kortom: een stack is een manier van een groep (normaal gesproken gerelateerde) gegevens aanspreken.

Wat voor voordeel dit zou kunnen hebben voor een database layer ontgaat me even, maar het kan zijn dat er toepassingen te verzinnen zijn waarbij een stack handig is.
Ontopic:

voor een goed gestructureerde aanpak van een database layer zou je eigenlijk eens moeten kijken naar JDBC, daar is al het abstractie-werk al voor je gedaan. Hoewel ik wel denk dat je dat soort dingen in PHP niet moet overdrijven, is het wel leuk om dat eens uit te werken.

Overigens heb ik je topictitel even aangepast, aangezien ik merk dat je in PHP5 aan de gang bent (wat nog niet echt gangbaar is ;))

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Acties:
  • 0 Henk 'm!

  • Skaah
  • Registratie: Juni 2001
  • Laatst online: 16-09 18:38
Hey, de regExp ken ik!

Ik snap niet waarom je Database MySQL laat extenden? Wat nu als je ineens switcht naar PostgreSQL? Bij wat je nu hebt kun je ook niet twee queries door elkaar laten lopen (twee for lussen).
Zoiets lijkt me mooi:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$db = new MySQLDatabase('mysql://root@localhost/test');

$query = new Query();
$query->setFields('merk','type');
$query->setTables('schoenen');
$query->addWhere('maat','=',42);
$query->addWhere('kleur','<>','rood');

$result = $db->select($query);

while($row = $result->fetchRow())
{
        print($row->field('merk'));
        printf('Er zijn %d schoenen gevonden',$result->numRows());
}

Met de volgende classes
code:
1
2
3
4
5
class Database
class MySQLDatabase extends Database
class Query
class QueryInterpreter
class MySQLQueryInterpreter extends QueryInterpreter

En dat je ergens in MySQLDatabase een MySQLQueryInterpreter object opslaat. Ofzo.

[edit]
Zo kun je ook gemakkelijk stored queries maken

[ Voor 43% gewijzigd door Skaah op 16-06-2004 18:57 ]


Acties:
  • 0 Henk 'm!

  • Maxonic
  • Registratie: September 2000
  • Laatst online: 05-09 22:23
Hey, de regExp ken ik!
:>

Maar met andere woorden. Ik kan 'Database' beter de 'Query' klasse (bij mij 'Result') laten extenden en dan 'QueryInterpreter' noemen.

Ik ga er even mee aan de slag. Laat later nog wel zien wat ik er van bak :)

Owja.. deze regel:

PHP:
1
$db = new MySQLDatabase('mysql://root@localhost/test');


Doe ik iets anders.
Ik gebruik de __autoload functie van PHP5. Ik maak dus een klasse 'Database' en of het nou MYSQL is of Oracle dat maakt verder niet uit. De klasse heet hetzelfde. Echter in een config file geef je aan welke database je gebruikt en afhankelijk van het geen je daar opgeeft laad hij een bepaald bestand met die klasse. Dus class.$database.db.php. In dat bestand staat vervolgens een include voor class.db.php wat de klasse 'DBParent' (bij jou dus 'Database') bevat. (en eventuele andere database onafhankelijke klassen)
Daarna wordt nog even gecontroleerd of de gelade klasse wel de klasse is waarin in de config file om is gevraagd. (regel 32 van class.db.php)
Dit heeft dus als voordeel dat je maar één string hoeft te veranderen om een ander soort database te gebruiken terwijl je anders alle [$db = new MySQLDatabase] stukjes door bijv. [$db = new OracleDatabase] moet vervangen.
Maargoed, dat doet er verder niet toe, geeft alleen even aan waarom mijn naamgeving zo is :)

[ Voor 71% gewijzigd door Maxonic op 16-06-2004 19:06 ]


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Maxonic schreef op 16 juni 2004 @ 18:53:
Ik gebruik de __autoload functie van PHP5. Ik maak dus een klasse 'Database' en of het nou MYSQL is of Oracle dat maakt verder niet uit. De klasse heet hetzelfde. Echter in een config file geef je aan welke database je gebruikt en afhankelijk van het geen je daar opgeeft laad hij een bepaald bestand met die klasse. Dus class.$database.db.php. In dat bestand staat vervolgens een include voor class.db.php wat de klasse 'DBParent' (bij jou dus 'Database') bevat. (en eventuele andere database onafhankelijke klassen)
Daarna wordt nog even gecontroleerd of de gelade klasse wel de klasse is waarin in de config file om is gevraagd. (regel 32 van class.db.php)
Dit heeft dus als voordeel dat je maar één string hoeft te veranderen om een ander soort database te gebruiken terwijl je anders alle [$db = new MySQLDatabase] stukjes door bijv. [$db = new OracleDatabase] moet vervangen.
Maargoed, dat doet er verder niet toe, geeft alleen even aan waarom mijn naamgeving zo is :)
Ik doe dat anders :p en wel op (ongeveer ;)) de volgende manier. Zie ook de Database::Factory method.
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
class MysqlException extends Exception
{
       public function __construct (&$Connection)
       {
              $this->message = mysql_error ($Connection);
              $this->code = mysql_errno ($Connection);
       }
}

class MysqlResult implements IResult
{
       private $Resource;
       public function __construct($Resource)
       {
              $this->Resource =& $Resource;
       }

       public function Fetch()
       {
              return mysql_fetch_assoc ($this->Resource);
       }
}

class DB_Mysql implements IDatabase
{
       private $Connection;
       public function __construct ($Username, $Password, $Database)
       {
              if (!mysql_connect ($Username, $Password))
              {
                     throw new MysqlException($this->Connection);
              }
       }

       public function & Query ($SQL)
       {
              return (new MysqlResult (mysql_query ($SQL, $this->Connection)));
       }

       public function NextId()
       {
              return mysql_insert_id($this->Connection);
       }
}

class MysqlQuery implements IQuery
{
       private $DB;
       public function __construct (IDatabase &$DB)
       {
              $this->DB =& $DB;
       }

       public function SelTopic ($TopicId)
       {
              return ($this->DB->Query ("SELECT * FROM topic WHERE id='{$TopicId}'"));
       }
}

class Database
{
       public static function & Factory ($Type, $Username, $Password, $Database)
       {
              echo $Query = "{$Type}Query";
              $DBType = "DB_{$Type}";
              $obj = new $Query(new $DBType($Username, $Password, $Database));
              return $obj;
       }
}

$_CONFIG['type'] = "Mysql";
$Query = Database::Factory($_CONFIG['type'],$_CONFIG['username'],$_CONFIG['password'],$_CONFIG['database']);

/*
 * Erg simpele interfaces, als voorbeeld.
 */
interface IDatabase
{
       public function Query();
       public function NextId();
}

interface IResult
{
       public function Fetch();
}

interface IQuery
{
       public function SelTopic($TopicId);
}

?>


PS, dit heb ik net even vlug ingetikt dus het kan zijn dat er wat foutjes in zitten

offtopic:
Wanneer komt er een PHP5 syntax-highlighter?
Pagina: 1