welke fetch mode?
Ozzie PHP op 24/05/2013 11:27:24:
Sowieso als ik geen fetch method meegeef dan default ik naar de assoc method. Maar wat inderdaad als je in de fetch class een constant aanmaakt die in een ander database type niet bestaat.
Bij PDO is dat trouwens al afgevangen heb ik gemerkt. Als ik een waarde ingeef die niet overeenkomt met een een van de constanten, dan default ie naar de BOTH fetch methode. Maar of iedere database dat zo netjes afhandelt is maar de vraag.
Wat ik zou kunnen doen is een beveiliging inbouwen, waardoor als een constant niet bestaat, hij automatisch terugvalt op de ASSOC methode.
Bij PDO is dat trouwens al afgevangen heb ik gemerkt. Als ik een waarde ingeef die niet overeenkomt met een een van de constanten, dan default ie naar de BOTH fetch methode. Maar of iedere database dat zo netjes afhandelt is maar de vraag.
Wat ik zou kunnen doen is een beveiliging inbouwen, waardoor als een constant niet bestaat, hij automatisch terugvalt op de ASSOC methode.
Je probleem begint al in deze regel:
(even daar gelaten of dit nu letterlijk wel of niet zo werkt, ik ga ervanuit dat je het op een manier werkend krijgt)
Hier krijg je al een foutmelding als ik nu opeens mijn nieuwe methode genaamd Ozzie_Fetch::INDIRECT gebruik. self::INDIRECT bestaat niet dus klapt je script eruit.
Oplossing 1: gebruik de switch die ik je eerder gaf en check op Ozzie_Fetch constantes. Als je een nieuwe daarin definieert kom je gewoon in de default terecht en blijft alles goed gaan.
Oplossing 2: zet er een try..catch omheen. Op zich zal het werken, maar ik zou er geen voorstander van zijn. In feite is het namelijk geen fout en is het gebruik maken van exceptions hier dus oneigenlijk gebruik. Maar daar moet je zelf maar een mening over vormen.
Ozzie PHP op 24/05/2013 11:27:24:
Hoe zou je dit volgens jou dan moeten ondervangen? Het enige wat ik me nu kan bedenken is dat je uitsluitend fetch methodes gebruikt die door alle databases worden ondersteund. Alleen dat zou dan weer betekenen dat ik fetch_class niet kan gebruiken, wat me nu juist weer heel handig lijkt. Of ik moet accepteren dat ik (voorlopig) alleen PDO kan gebruiken (waar ik op dit moment overigens geen bezwaren in zie).
Ook hier zie ik twee manieren:
1) in classes die het niet ondersteunen geef je de algmene default terug. Deze bepaal jezelf is bijvoorbeeld ASSOC. Elke aanroepende class zal dus zelf moeten checken of wat terugkomt is waarom is gevraagd (je classes), of de default en daarnaar moeten handelen.
2) je schrijft een adapter die de niet ondersteunde fetch methode simuleert. Stel je hebt een nieuwe database class die die FETCH_CLASS niet ondersteunt. Die geeft dus de default terug. De adapter vangt die op en bouwt het om naar de gevraagde classes. De aanroepende class uiteindelijk krijgt dan weer terug wat nodig was, zonder zich er verder zorgen om te hoeven maken. De adapter kan je overigens tussen de database interface (PDO) en de database class zetten, of tussen de database class en de aanroepende class.
En een min of meer 3e manier:
3) simuleer de nieuwe fetch methode in de database class. In dit geval zal de database class dus doen wat in optie 2 de adapter doet. Niet helemaal netjes overigens, want daardoor geef je je database clas in mijn ogen een taak die het niet zou moeten hebben.
"Hier krijg je al een foutmelding als ik nu opeens mijn nieuwe methode genaamd Ozzie_Fetch::INDIRECT gebruik. self::INDIRECT bestaat niet dus klapt je script eruit."
Nee, hij klapt er niet uit. Ik krijg wel een warning dat de constant dan niet bestaat, maar hij klapt er niet uit. Om dit netjes op te lossen zou ik wel kunnen kijken of de betreffende constant bestaat en zo niet dan defaulten naar 'assoc', maar ik weet niet of dat zin heeft omdat je dan toch een ander resultaat krijgt dan verwacht. Misschien kan ik dan nog beter een fatal error gooien zodat ik direct in de smiezen heb dat er iets fout gaat.
Wat betreft de 3 laatste manieren:
1) Dit heeft denk ik geen zin, omdat je dan iets anders terugkrijgt dan dat je verwacht.
2) Dat klinkt ingewikkeld.
3) Dit lijkt me wel wat, omdat ik dan alle code in 1 class (de db class waar het om gaat) kan houden.
Mijn voorkeur gaat uit naar manier 3. Maar stel nu we nemen als voorbeeld weer de fetch_class methode. En dan kom ik eigenlijk terecht bij dezelde vraag als ik mijn andere topic. Hoe kan je zo'n fetch_class methode simuleren? Ik kan me niet voorstellen hoe je dat zou moeten doen? Ja, het kan wel, maar dan moet je alle classes daar op voor bereiden. Ik gebruik private properties. Die kun je nooit van buitenaf setten. Dat zal altijd van binnenuit moeten. Via de PDO::FETCH_CLASS methode werkt dit wel. Ik denk dus dat je dit niet kunt ondervangen voor andere databases, maar als jij denkt dat dat wel kan hoor ik het natuurlijk graag!
(Weet jij of er uberhaupt andere databases zijn die ook zo'n fetch_class methode hebben?)
Ozzie PHP op 24/05/2013 12:13:07:
2) Dat klinkt ingewikkeld.
3) Dit lijkt me wel wat, omdat ik dan alle code in 1 class (de db class waar het om gaat) kan houden.
3) Dit lijkt me wel wat, omdat ik dan alle code in 1 class (de db class waar het om gaat) kan houden.
3 is net zo ingewikkeld als 2, maar de opmerking die je bij 3 plaatst is eigenlijk niet waar....
Als je namelijk de ASSOC resultaten moet omzetten naar classes (omdat de betreffende database interface die niet ondersteunt) dan is dat werk dat je moglijk vaker zal moeten doen. Voor elke database interface die die fetch methode niet ondersteunt zal je die omzet code moeten hebben. Plaats je dat in de database class zelf, dan zal je het dus vaker moeten doen. Plaats je het in een adapter dan doe je 1 keer en nooit weer!
Hoe je echter data in private properties kan gieten dat weet ik niet, zal ik eens naar gaan zoeken. Maar heb je niet een methode in je classes zitten om met behulp van 1 array direct alle data te setten? Dat is een bijzonder simpele methode om te schrijven en ben je direct van het probleem af.
Andere database interfaces (of extensies, niet databases zoals jij ze noemt) dan PDO heb ik geen ervaring mee. Of er dus andere zijn die wel of niet FETCH_CLASS ondersteunen kan ik je niet vertellen.
Als ik je goed begrijp zeg je eigenlijk... is het niet slimmer om die fetch_class niet te gebruiken, maar via een array de properties te setten? Dat zou inderdaad ook kunnen. Ik heb nog nooit met zo'n adapter gewerkt om eerlijk te zijn. Kun je daar een klein voorbeeldje van geven zodat ik snap hoe zoiets werkt?
"Hoe je echter data in private properties kan gieten dat weet ik niet, zal ik eens naar gaan zoeken'."
Dat zou mooi zijn als je daar iets voor kan vinden. Maar ik denk dat dit altijd van binnenuit de class zal moeten gebeuren. Wat dat betreft is die fetch_class methode wel mooi.
"Maar heb je niet een methode in je classes zitten om met behulp van 1 array direct alle data te setten? Dat is een bijzonder simpele methode om te schrijven en ben je direct van het probleem af."
Nee, zover ben ik helaas nog niet.
"Andere database interfaces (of extensies, niet databases zoals jij ze noemt) dan PDO heb ik geen ervaring mee. Of er dus andere zijn die wel of niet FETCH_CLASS ondersteunen kan ik je niet vertellen."
Oké.
Ozzie PHP op 24/05/2013 12:29:40:
Als ik je goed begrijp zeg je eigenlijk... is het niet slimmer om die fetch_class niet te gebruiken, maar via een array de properties te setten? Dat zou inderdaad ook kunnen. Ik heb nog nooit met zo'n adapter gewerkt om eerlijk te zijn. Kun je daar een klein voorbeeldje van geven zodat ik snap hoe zoiets werkt?
Nee, ik probeer geen mening te geven over het wel of niet gebruik van FETCH_CLASS. Ik zeg alleen dat als je ook die setter hebt in je classes dan kan je daar op momenten dat het nodig is simpel gebruik van maken. Niet alleen hier overigens.
Een adapter is een heel simpele class die iets omzet naar iets anders (leuk, zo cryptisch). Denk bijvoorbeeld aan de stroomadapter die je gebruikt als je je Nederlandse laptop in Amerika wil opladen. Je stekker past daar niet, dus je gebruikt een adapter. Aan de ene kant heeft die een ingang voor jou stekker, aan de andere kant een uitgang voor een Amerikaans stopcontact. Jouw stekker ziet iets wat die kent, het Amerikaanse stopcontact ziet iets wat die kent en iedereen is gelukkig.
Een adapter class werkt net zo. Ik wil er wel een voorbeeld voor maken, maar dat kost even wat meer werk. Lees anders eerst even iets over dat pattern op wikipedia, als dat niet genoeg is kan ik later vandaag wel kijken of ik iets in elkaar kan zetten om het (hopelijk) duidelijk te maken voor deze database classes.
http://en.wikipedia.org/wiki/Adapter_pattern
Oké, ik snap wat je bedoelt. Maar om EN FETCH_CLASS te gebruiken EN een setter, dat lijkt me weer dubbelop. FETCH_CLASS is makkelijk, maar heeft dus als nadeel dat het in andere db interfaces (zie je het, ik schrijf interfaces :-) ) niet wordt ondersteund. Maar is dat erg (aangezien ik geen reden zie om af te stappen van PDO). Zo'n setter is meer werk om te integreren in ieder class, maar wordt dan wel altijd ondersteund. Wat zou nu doorslaggevend moeten zijn is de vraag. Iets wat NU makkelijk werkt, of iets wat je MISSCHIEN in de TOEKOMST ooit zal gaan gebruiken (waarvoor ik echter op dit moment geen enkele reden zie).
"Aan de ene kant heeft die een ingang voor jou stekker, aan de andere kant een uitgang voor een Amerikaans stopcontact. Jouw stekker ziet iets wat die kent, het Amerikaanse stopcontact ziet iets wat die kent en iedereen is gelukkig."
Kijk, dat is een lekker duidelijke uitleg :)
"als dat niet genoeg is kan ik later vandaag wel kijken of ik iets in elkaar kan zetten om het (hopelijk) duidelijk te maken voor deze database classes."
Dat zou wel fijn zijn, maar niks uitgebreids hoor. Kost je anders veel te veel tijd. Het gaat me vooral om het principe. Dus ik geef een constante voor een fetch method mee. De database ondersteunt deze fetch mode niet en de vraag is dan hoe zo'n adapter het dan wel werkend krijgt.
Ozzie PHP op 24/05/2013 12:29:40:
"Hoe je echter data in private properties kan gieten dat weet ik niet, zal ik eens naar gaan zoeken'."
Dat zou mooi zijn als je daar iets voor kan vinden. Maar ik denk dat dit altijd van binnenuit de class zal moeten gebeuren. Wat dat betreft is die fetch_class methode wel mooi.
Dat zou mooi zijn als je daar iets voor kan vinden. Maar ik denk dat dit altijd van binnenuit de class zal moeten gebeuren. Wat dat betreft is die fetch_class methode wel mooi.
check: http://www.phphulp.nl/php/forum/topic/objects-instantieren-met-data-al-in-private-properties/90837/
Toevoeging op 24/05/2013 18:58:25:
Even een schematisch voorbeeld van hoe het zou kunnen werken met een adapter.
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Situatie:
+-----------+ +-------------------+ +--------------------+
| aanvrager | | Je database class | | database interface |
+-----------+ +-------------------+ +--------------------+
Vraagt CLASS -> kent geen CLASS
zet om naar ARRAY -> haalt gegevens op
probleem <- geeft array terug <- plaatst in array
wil geen array
+-----------+ +-------------------+ +--------------------+
| aanvrager | | Je database class | | database interface |
+-----------+ +-------------------+ +--------------------+
Vraagt CLASS -> kent geen CLASS
zet om naar ARRAY -> haalt gegevens op
probleem <- geeft array terug <- plaatst in array
wil geen array
Dit is dus wat er zou gebeuren en wat je niet wil. De database interface kan je niet veranderen. De database class will je niet veranderen (uitgangspunt 3 nogmaals). De aanvrager wil je niet laten testen op wat de return is, die wil je gewoon met de objecten laten werken. Tussen de aanvrager en je database class zet je dus een adapter. Richting de aanvrager doet die zich voor als een database class (met andere woorden, implementeert dezelfde interface als je database class). Elke methode zal de adapter dus ook implementeren, alleen waar niets hoeft te gebeuren zal de adapter het request gewoon direct doorzetten naar je database class.
Voor de database class verandert er nu niets, die krijgt gewoon requests (alleen vanuit de adapter, maar dat maakt hem niets uit). Komt er nu een CLASS fetch request dan gebeurt er dit:
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
+-----------+ +-------------------+ +--------------------+
| aanvrager | | adapter | | Je database class |
+-----------+ +-------------------+ +--------------------+
Vraagt CLASS -> onthoudt CLASS
vraagt ARRAY -> zet verzoek door
herinnert CLASS <- geeft array terug
converteert ARRAY
Helemaal happy <- geeft CLASS terug
| aanvrager | | adapter | | Je database class |
+-----------+ +-------------------+ +--------------------+
Vraagt CLASS -> onthoudt CLASS
vraagt ARRAY -> zet verzoek door
herinnert CLASS <- geeft array terug
converteert ARRAY
Helemaal happy <- geeft CLASS terug
Kortweg in code:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class Database_Adapter implements Database_Interface{
private $databaseObj;
public function __construct( Database_Interface $database ){
$this->databaseObj = $database;
}
public function getRows( $method ){
if ( $method == Ozzie_Fetch::CLASS ){
$array = $this->databaseObj->getRows( Ozzie_Fetch::ASSOC );
return $this->convert_array_to_class( $array );
} else {
return $this->databaseObj->getRows( $method );
}
}
}
?>
class Database_Adapter implements Database_Interface{
private $databaseObj;
public function __construct( Database_Interface $database ){
$this->databaseObj = $database;
}
public function getRows( $method ){
if ( $method == Ozzie_Fetch::CLASS ){
$array = $this->databaseObj->getRows( Ozzie_Fetch::ASSOC );
return $this->convert_array_to_class( $array );
} else {
return $this->databaseObj->getRows( $method );
}
}
}
?>
Gewijzigd op 24/05/2013 19:00:31 door Erwin H