PDO objekt deling...

Tags:    php pdo

Hej venner :-)

Jeg kunne godt tænke mig at høre jeres mening om følgende:

Jeg har haft funderet en del over hvordan man bedst deler et PDO objekt mellem flere forskellige objekter som skal interagere med databasen. Jeg har ikke kunnet finde nogen svar konkrete svar nogen steder - og jeg har set folk gøre det på mange måder. Det er nok ikke specifikt for pdo - det gør sig nok gældende for, for eksempel, mysqli.

Man kunne give db-objektet gennem constructors. Eller man kunne have det i en variabel, som man gav objektet adgang til via global keywordet. Man kunne også overveje, om det overhovedet er et problem at have flere forskellige instances af PDO objektet. Jeg har ikke testet det, da min logik siger at én forbindelse der deles mellem alle er bedre end en forbindelse per objekt.

Der er mange muligheder. Jeg er dog kommet frem til en metode som jeg synes er den mest optimale - men den er lidt rough. Og selvom jeg synes den er funktionel nok - så er jeg usikker på om det er "the way to go".

Det ser således ud:
Fold kodeboks ind/udPHP kode 


Når jeg så skal bruge min connection gør jeg bare noget ala:
Fold kodeboks ind/udPHP kode 


Nemt og fikst synes jeg selv.

Kan i finde nogen svagheder ved den metode? Eller er der nogen helt åbenlyse ting som overser - som gør det fuldstændigt overflødigt?



Indlæg senest redigeret d. 22.04.2012 19:03 af Bruger #17015
9 svar postet i denne tråd vises herunder
2 indlæg har modtaget i alt 6 karma
Sorter efter stemmer Sorter efter dato
Man siger gerne at singleton er et anti-pattern. Grundet at Singletons vist nok ikke tillader Dependency Injection.

Men alternativt kan du som jeg skrev tidl. bruge en wrapper, der gør brug af singleton og registry pattern. Anvendeligheden er den samme - men det giver mulighed for DI.

Fold kodeboks ind/udPHP kode 




Indlæg senest redigeret d. 23.04.2012 15:18 af Bruger #10216
Man siger at, globale variabler er vejen til forvirring. :)

Men det kommer lidt an på hvilken vej du vil gå - men som udgangspunkt, hvis du vil bruge OOP, så nøjes med det og undgå procedural kode. Men du kan bruge registry-pattern, et singleton-pattern.

Singleton - det betyder dog at du skal lave en wrapper:
Fold kodeboks ind/udPHP kode 


Registry:
Fold kodeboks ind/udPHP kode 



Jeg arbejder pt. med en blanding af disse, hvor det så tillader mig at lave objekt-instanser af en wrapper klasse.




Ja jeg glemte at nævnte singleton mønstret.

Ja - globale variable er farlige - derfor prefixer jeg dem - som fx $_dbh - og så længe man holder det i det små er det vel fint. Jeg har også hørt mange kritiske ryster omkring singleton-metoden. :-) Jeg kan dog ikke huske hvad det konkret handlede om - dog var det på et ret teoretisk plan.

Men i store træk så er idéen i både singleton-klassen og mine to funktioner jo det samme. Formen er bare forskellig :-)

Man burde nok holde rene-linjer og tage singleton udgaven.



Singleton ér et kæmpe antipattern, men du kan jo bruge en factory. Det har jeg selv brugt meget i et større system, og det virker EXCELLENT!!!

Her er lidt af min factory:
Fold kodeboks ind/udPHP kode 


En hel masse metoder er undladt. Mit Context objekt ved, hvordan alting instantieres, så hvis jeg ændrer på en constructor, så skal jeg kun ændre i min Context implementation, så kører det igen.

De fleste objekter, som Context klassen opretter, bliver cachet (det er den første linje i funktionen.

Factory object er et skidegodt pattern!!



Det kan godt være jeg ikke fatter hvordan interfaces virker - men umiddelbart ser jeg dem mest funktionelle i projekter med mange forskellige programmører.

Det er som en abstrakt klasse som en almindelig klasse udvider. Bortset fra at et interface blot siger, at en klasse der udvider denne SKAL implementere en række metoder.

Dog er jeg ikke sikker på hvordan properties i et interface håndteres. Er de delt mellem interfaces?

Mit mål er at have flere objekter der bruger samme instans af et PDO objekt. Som for eksempel løses med Michaels singleton-løsning, eller globale variable/funktioner hvor det er tilgængeligt. Jeg er ikke helt sikker på at man kan gøre det samme med et interface...

Men dit objectCache array er en property i interfacet, som nedarves til klassen - korrekt?

Jeg synes det virker som en skidt løsning at skulle have den der isset-if-else snippet alle steder.

Men det kan være jeg bare er blank.

I hvert fald virker Singleton løsningen mest elegant. Den minder også meget om mit oprindelige udkast - funktionaliteten er den samme - min er bare ikke pakket ind i en klasse.



Interfaces bør ikke have properties (i mange sprog kan de slet ikke).
Det er en slags kontrakt, hvor du lover, at din klasse implementerer en række metoder, men intet siger, omkring hvordan du vil implementere dem.

Nogle af mine DAO'er har en hardkodet liste af data, hvor en database er overkill. Andre gange bruger de en XML fil og andre gange igen læser jeg data fra en web server.

Interfaces er også rare i unit testing øjemed, for da kan du lave en stub, hvor metoderne kan garanteres samme udfald. Det kan du ikke, hvis udfaldet afhænger af tilgængeligheden og indholdet af f.eks. en database.



I så fald ved jeg ikke helt hvordan du har tænkt dig at løse problemet med deling af et enkelt database handle med interfaces.

Hvis ikke din objectcache er delt mellem objekterne - hvordan fungerer det så?



I min frontend kode har jeg noget i stil med følgende:

Fold kodeboks ind/udKode 


Mit 'builder' objekt skal faktisk bruge et game DAO objekt, men det ved jeg ikke, når jeg laver frontend kode. Da tager jeg bare det objekt, som bliver returneret af getBuilder() metoden.

Jeg skal så også bruge et game DAO objekt selv, og det skal så bruge en hel masse andet (bl.a. en database forbindelse som builder objektet også skal bruge).

Alt dette bagvedliggende ved kun mit context objekt, som implementerer factory pattern.

Context cacher også de oprettede objekter, så det objekt, getGameDAO() returnerer, er det samme som det, getBuilder() skaffer til builder objektet.



jeg hopper med på singleton vongen.

personligt har jeg en global var som hedder $lib som indeholder alle de klasser jeg normalt bruger.

etc, init_lib.php
$lib = new stdClass();
$lib->db = new Database();

og bruger så:
$lib->db->prepare(....);



t