Ik heb wat kleine dingen veranderd aan dit script en ik heb ipv standaard queries gebruik gemaakt van de PDO 'plugin' van php.
Met standaard programmeren (dus niet OOP) werkt PDO perfect. Maar zo gauw ik dit in mijn class verwacht krijg ik de Error:
"Fatal error: Call to a member function quote() on a non-object in C:\wamp\www\classes\Auth\clsAuthentication.php on line 29"
Ik heb wel een oplossing, de PDO connection in de constructor zetten, maar dit is ver van praktisch. Volgens mij is extenden ook niet een goede oplossing.
Weet iemand hoe ik dit werkend krijg ?
Op dat punt is $db niet bekent.
Er zijn eigenlijk een paar mogelijkheden:
een class om pdo schrijven die singleton is waardoor je ter plekke een instance kunt "maken" en gebruiken
De $db variabele meegeven aan de class (en dus binnen de class opslaan)
Een registry class schrijven waar je de variabele $db aan meegeeft, die classe kun je dan overal om die variabele vragen
oplossing 2 is misschien het makkelijkst, maar het ligt meestal aan de omgeving wat hier het handigste is.
Ben je van plan veel gebruik te maken van de database, dan is het inderdaad interessant om de registery class te gebruiken. Zoals hierboven gezegd kan je dan gewoon de database aanroepen wanneer je wilt (omdat registry een singleton is). Maar gebruik je gewoon even snel een connectie naar de database, dan kan jet het ook zo doen:
<?php
class Myclass
{
protected $connection;
public function __construct(PDO $connection)
{
$this->connection = $connection;
}
public function myfunction()
{
$this->connection->query("SELECT * FROM table");
// continue..
}
}
?>
<?php
$connection = new PDO('mysql:host=localhost;dbname=db', 'user', 'pass');
$myclass = new Myclass($connection);
?>
<?php
class Register {
static public function DB() {
static $db;
if(!$db) {
$db = new PDO('mysql:host='.SERVER.';dbname='.DB, USER, PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return $db;
}
}
// Dan kan je het op de volgende manier pdo aanroepen
public function findById($id) {
$pdo = Register::DB();
$stmt = $pdo->prepare
// enz
}
?>
Normaal gesproken geef je de klasses die je nodig hebt mee via de constructor maar omdat een database class zo centraal staat vind ik dit ook wel een mooie oplossing. Het Register kan je dan ook voor andere dingen zoals een template engine gebruiken.
Ik gebruik zelf de eerste, omdat je dan volledige controle hebt over welke instantie van PDO je klasse gebruikt (mocht je meerdere databases gebruiken)
Oplossing 2 is een beetje twijfelachtig, omdat je de klasse moet kennen wil je weten dat je een global variabele nodig hebt, je de variabele gemakkelijk kan vervangen met iets verkeerts, ook per ongeluk waardoor plotseling de zooi niet meer werkt. En al je klassen maken gebruik van dezelfde PDO instantie.
Oplossing 3 is niet te doen. Dat zou inhouden dat iedere instantie een eigen verbinding opzet, en dat je de constructor als het ware kwijt bent aan PDO, je zal iedere instantie al de verbindingsgegevens mee moeten geven. Dat is nog erger dan oplossing 1. Erger, je extend PDO om functionaliteit terwijl je eigenlijk alleen moet extenden wanneer een klasse een specifiekere variant is van een andere klasse. Extenden doe je bij een "is een", niet bij "gebruikt een". Extend je PDO, kan je niets anders meer extenden.
In mijn ogen is oplossing nummero uno de prettigste. $pdo aan de constructor meegeven is relatief weinig moeite en geeft je toch de meest makkelijk te begrijpen code en de meeste flexibiliteit.
Ik ga dan maar voor optie 1, ik had een mooier oplossing verwacht. Als die er niet is word het lastig, en bij nader inzien is het niet een hele slechte oplossing.
Met optie 2 en 3 gaat de 'flexibiliteit' erg omlaag.
Optie 2 zou je ook nog ietsjes anders kunnen doen, zodat je niet last hebt van het risico dat de variabele ineens verdwenen is. Je zou een gewone functie kunnen maken die een verbinding teruggeeft.
<?php
function database()
{
static $pdo;
if(!$pdo) {
$pdo = new PDO('...');
}
return $pdo;
}
?>
Of belachelijk kort
<?php
function database()
{
static $pdo;
return $pdo ? $pdo : $pdo = new PDO('...');
}
?>
Op deze manier kan je database instantie niet worden overschreven, wordt hij pas aangemaakt wanneer hij echt nodig is, en krijg je een duidelijke foutmelding dat er iets mis is. Je houdt het probleem dat je maar 1 verbinding binnen alle instanties kan gebruiken. Maar in voornamelijk kleine applicaties zou dat niet een probleem hoeven zijn. En dan is het wel makkelijk.
<?php
class Foo {
public function find($id)
{
$stmt = database()->prepare('SELECT * FROM tabel WHERE id = :id');
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
if($stmt->execute()) {
return $stmt->fetch(PDO::FETCH_ASSOC);
} else {
return false;
}
}
}
?>