Extend om SQL te gebruiken

Status
Niet open voor verdere reacties.

Niellles

Gebruiker
Lid geworden
21 jun 2008
Berichten
194
Beste,

Ik ben mij aan het oriënteren op classes etc.

Ik heb een bestand, config.inc.php in de submap includes:
PHP:
<?php
/**
 * @author Niels
 * @copyright 2013
 */
$config['MySQL_host'] = 'localhost';
$config['MySQL_user'] = 'root';
$config['MysSQL_password'] = '';
$config['MySQL_database'] = 'recept';

#####################################
## Hier onder niets veranderen.    ##
#####################################

// Benodigde bestanden ophalen.
require_once(dirname(_FILE_).'/functions.inc.php');
require_once(dirname(_FILE_).'/classes.inc.php');
?>

Nu wil ik eigenlijk in al m'n classes wel MySQL gebruiken en ik heb bedacht dat ik al m'n classes extend op 1 class waarin een connectie maak, ongeveer zo:
PHP:
<?php

/**
 * @author Niels
 * @copyright 2013
 */
class sql { // We willen graag in alle classes een MySQL verbinding.
 function __costruct($config){
    $link = mysqli_connect($config['MySQL_host'],$config['MySQL_user'],$config['MysSQL_password'],$config['MySQL_database']);
 }
}

class recept extends sql{
 public $id;
 public $ingredient;
 public $beschrijving;
 public $van;
 public $tot;
 
 function __construct($args){ // Bij het aanmaken van nieuw object alvast het één en ander doen.
    parent::__construct();
    
    $actions = array('nieuw','random','get'); //We willen één van deze actions!
    
    if (empty($args['action']) || !in_array($args['action'],$actions)){
        return false; // De actie is niet correct!
    }
    
    foreach($args as $key => $value){ // $args omschrijven en vernietigen.
        $key = $value; 
        unset($args[$key]);
    }
    
    if ($action == 'nieuw'){ // We willen een leeg object maken.
        return true;
    }
    elseif ($action == 'get'){ // We willen een specifiek recept ophalen.
        return true;
    }
    elseif ($action == 'random'){ // We willen een willekeurig recept, maar niet de vorige.
        $result = mysqli_query($link,"SELECT * FROM `recepten` WHERE `id` <> $id ORDER BY rand() LIMIT 1");
        $obj = mysqli_fetch_object($result);
        
        $this->id = $obj->id;
        $this->ingredient = $obj->ingredient;
        $this->beschrijving = $obj->beschrijving;
        $this->van = $obj->van;
        $this->tot = $obj->tot;
 
        return true;
    }
    else{ // Dit mag nooit gebeuren!
        return false;
    }
    
  }
}

class user extends sql{
 function iets($string)
 {
    echo $string;
 }
}
?>

Dit werkt als het goed is... maar hebben de classes user en recept nu iets met elkaar te maken, behalve een gezamenlijke parent?
Verder vind ik regels 44 t/m 48 er wat vreemd uit zien... dat moet toch makkelijker kunnen?

Iemand die kan helpen?

Niels
 
Laatst bewerkt:
maak in je sql class een static variable $_instance = Null
In je constructor controleer je of
if($_instance == Null) (self::$_instance = $this}
return self::$_instance.

De constructor zal dus een instance van zich zelf teruggeven.

ook maak je een static public function getInstance()
die kijkt ook of $_instance niet null is en geeft dan de instance terug
en anders doe je een thrown exception() of die()

dan kun je met $db = SQL::getInstance overal over de connection beschikken!
 
Hoi Phobia,

Fijn dat je wilt meedenken.
self:: enzo heb ik helaas nog geen kaas van gegeten, de documentatie word ik helaas ook nog niet veel wijzer uit. Ik heb nu het volgende staan:
PHP:
class sql { // We willen graag in alle classes een MySQL verbinding.
 static $_instance = NULL;
 
 function __costruct($config){
    $link = mysqli_connect($config['MySQL_host'],$config['MySQL_user'],$config['MysSQL_password'],$config['MySQL_database']);
    if($_instance == Null){
    self::$_instance = $this;}
 }
 
 public static function getInstance(){
    if($_instance == Null){
        if (!self::$_instance = $this){
            throw new Exception('Geen database connectie.');
        }
    }
 }
}

class recept {
 public $id;
 public $ingredient;
 public $beschrijving;
 public $van;
 public $tot;
 
 
 function __construct($args){ // Bij het aanmaken van nieuw object alvast het één en ander doen.
    parent::__construct();
    try {
        $link = sql::getInstance();   
    } catch(Exception $e) {
        die($e->getMessage());
    }
(...)

Maar nu geef ik nog nergens de array (met variabelen voor de connectie) die ik config.inc.php definieer mee... Kan je me vertellen waar m'n denkfout zit?
 
Laatst bewerkt:
PHP:
class sql { // We willen graag in alle classes een MySQL verbinding.
 static $_instance = NULL;
 
 function __construct($config){
    $link = mysqli_connect($config['MySQL_host'],$config['MySQL_user'],$config['MysSQL_password'],$config['MySQL_database']);
    if($_instance == Null){
    self::$_instance = $link;
}
return self::$_instance;// dat krijg je gelijk je connectie terug om mee te werken
 }
 
 public static function getInstance(){
    if($_instance == Null){
            throw new Exception('Geen database connectie.');
    }
    return self::$_instance;
 }
}
 
class recept {
 public $id;
 public $ingredient;
 public $beschrijving;
 public $van;
 public $tot;
 
 
 function __construct($args){ // Bij het aanmaken van nieuw object alvast het één en ander doen.
    
    try {
        $this->link = sql::getInstance();  // $this, dan kun je hem door je hele class gebruiken!
    } catch(Exception $e) {
        die($e->getMessage());
    }
(...)

buiten de classes doe je dan 1 maal $db = sql("credits here");
of de eerste keer dat je de link nodig hebt doe je dat
op dat moment is de verbinding gemaakt en opgeslagen in de sql class
Over al is de link nu op te roepen met sql::getInstance()

Ik sla $this op in de variabele omdat ik een sqlwrapper/sqladapter gebruik samen met PDO

kijk eens naar singleton pattern!
 
Laatst bewerkt:
Ik heb er nu het volgende van gemaakt:

Index.php:
PHP:
<?php
include('includes/config.inc.php');

$recept = New recept(array('action' => 'nieuw'));
?>

config.inc.php:
PHP:
<?php
$config['MySQL_host'] = 'localhost';
$config['MySQL_user'] = 'root';
$config['MysSQL_password'] = '';
$config['MySQL_database'] = 'maaltijd';

#####################################
## Hier onder niets veranderen.    ##
#####################################

// Benodigde bestanden ophalen.
require_once('includes/functions.inc.php');
require_once('includes/classes.inc.php');
$link = New sql($config);
?>

En een stukje classes.inc.php:
PHP:
class sql { // We willen graag in alle classes een MySQL verbinding.
 static $_instance = NULL;
 
 function __construct($config){
    $link = mysqli_connect($config['MySQL_host'],$config['MySQL_user'],$config['MysSQL_password'],$config['MySQL_database']);
    if(empty($_instance)){
    self::$_instance = $link;
    }
        return self::$_instance;// dat krijg je gelijk je connectie terug om mee te werken
 }
 
 public static function getInstance(){
    if(empty($_instance)){
            throw new Exception('Geen database connectie.');
    }
    return self::$_instance;
 }
}

class recept {
 public $id;
 public $ingredient;
 public $beschrijving;
 public $van;
 public $tot;
 
 
 function __construct($args){ // Bij het aanmaken van nieuw object alvast het één en ander doen.     
    try {
        $link = sql::getInstance();   
    } catch(Exception $e) {
        die($e->getMessage());
    }
(...)

In eerste instantie gaf hij twee keer de foutmelding unknown variable _instance op de regels met de vergelijking $_instance == null, daarom heb ik empty() gebruikt... Maar nu geeft hij alsnog de melding Geen database connectie. Hij probeert het in ieder geval wel, want als ik verkeerde waardes geef in $config dan krijg ik daar een melding van.

Er loopt dus nog steeds iets niet helemaal lekker, ik zal eens even kijken of het na het lezen over het singleton pattern duidelijk wordt.

Alvast bedankt!
 
PHP:
public static function getInstance(){
    if(self::$_instance == Null){
            throw new Exception('Geen database connectie.');
    } else  {
    return self::$_instance;
}
 }
 
Laatst bewerkt door een moderator:
al m'n classes extend op 1 class waarin een connectie maak, ongeveer zo:

Dat moet je niet doen. Extenden doe je wanneer je de functionaliteit van de basisclasse wilt uitbreiden en dat doe je juist niet; je voegt functionaliteit toe aan de class die je zou laten extenden op de SQL class.

Wat je zoekt is "composition" en "dependency injection". Je maakt aan het begin van je script een databaseverbinding en die verbinding geef je als parameter door aan de constructors van de classes die die verbinding nodig hebben.

Ik zie ook static constructors voorbij komen en het woord "instance", dat ruikt naar een singleton en dat is meestal ook niet de juiste oplossing. Dat je nu maar één verbinding gebruikt betekent niet dat je jezelf programmatisch wilt beperken tot absoluut altijd maar één verbinding.
Als je bijvoorbeeld een langdurie handeling uitvoert en je wilt tussentijds de status ophalen, dan zul je twee verbindingen tegelijk moeten kunnen openen zodat de ene verbinding de operatie uitvoert in een transactie, en de andere verbinding de status kan updaten buiten de transactie om.

Wat je krijgt is dus iets als:

PHP:
class sql {
 private $rConnection=null;
 
 function __construct($config){
    $rConnection = mysqli_connect($config['MySQL_host'],$config['MySQL_user'],$config['MysSQL_password'],$config['MySQL_database']);
    }
 }

public getConnection()
{
return $this->rConnection;
}
}
 
class recept {
 private $objDbConnection;

public __construct($pObjConnection)
{
  $opbjDbConnection = $pObjConnection;
}

En dan is het weer gebruikelijk om de "sql" class uit te breiden met methods als "query()" zodat je dat object ook direct kunt gebruiken om queries uit te voeren en de resultaten op te vragen. Dat maakt het eenvoudiger om je database te beveiligen tegen injectie, en het maakt loggen en benchmarken een stuk eenvoudiger. Een fijne plus is dat het ook eenvoudiger wordt om meerdere databasemerken te gaan ondersteunen door gewoon een instantie van een andere "sql" class door te geven.
 
Ook dat klinkt wel aardig, ik wil echter de arguments in m'n construct al voor andere zaken gebruiken... Heb je daar toevallig ook nog een oplossing voor?

Verder zal ik voorlopig maar 1 connectie nodig hebben.

M'n SQL class uitbreiden met andere methods klinkt wel weer interessant.

De oplossing van Phobia werkt op dit moment als een zonnetje trouwens!
 
Ook dat klinkt wel aardig, ik wil echter de arguments in m'n construct al voor andere zaken gebruiken... Heb je daar toevallig ook nog een oplossing voor?

De argumenten van je constructor gebruik je voor alle data die je bij eht maken van het object nodig hebt, daar kan ene databaseverbinding ook bij horen.
Maar als je dat echt niet wilt dan kun je de depedency ook injecteren door een method te maken als "registerDatabaseConnection()" waaraan je de verbinding meegeeft vlak na het maken van het object en vlak voordat je hem gaat gebruiken. Dat heeft weer als voordeel dat die method voor elke class hetzelfde kan heten en je dus niet hoeft uit te zoeken in welke parameter de verbinding wordt meegegeven.

Als je de verbinding maar doorgeeft aan het object, en niet het object de verbinding laat ophalen uit de omgeving want dan wordt het een zootje.

Wat phobia doet kan opzich best, maar op de lange termijn heeft dat z'n beperkingen.
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan