db connection voor MySQL via een class

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Nkamp Kamp van de

nkamp Kamp van de

09/12/2012 22:10:40
Quote Anchor link
Hallo,

Ik heb destijds het boek "het beste van PHP en MySQL" gekocht en doorgelezen. Daarin vond ik de volgende constructie voor een connectie:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php # config.inc.php
/**
 * Algemene configuratie
 */

if ($_SERVER['SERVER_ADDR'] == '127.0.0.1') {
    // Lokale MySQL-databaseserver
    define('MYSQL_SERVER',         'localhost');
    define('MYSQL_GEBRUIKERSNAAM', 'user');
    define('MYSQL_WACHTWOORD',     'wachtwoord');
    define('MYSQL_DATABASENAAM',   'database naam');
    // Lokaal alle foutmeldingen weergeven
    error_reporting(E_ALL | E_STRICT);
}
else {
    define('MYSQL_SERVER',         'server');
    define('MYSQL_GEBRUIKERSNAAM', 'user');
    define('MYSQL_WACHTWOORD',     'wachtwoord');
    define('MYSQL_DATABASENAAM',   'databasenaam');
    // Alle foutmeldingen op de live server uitschakelen
    error_reporting(0);
}


/**
 * Configuratie voor mysql_connect() zonder argumenten
 * @link http://www.php.net/manual/en/mysql.configuration.php
 */

@ini_set('mysql.default_host',     MYSQL_SERVER);
@
ini_set('mysql.default_user',     MYSQL_GEBRUIKERSNAAM);
@
ini_set('mysql.default_password', MYSQL_WACHTWOORD);

/**
 * Configuratie voor mysqli_connect() zonder argumenten
 * @link http://www.php.net/manual/en/mysqli.configuration.php
 */

if (extension_loaded('mysqli')) {
    @
ini_set('mysqli.default_host', MYSQL_SERVER);
    @
ini_set('mysqli.default_user', MYSQL_GEBRUIKERSNAAM);
    @
ini_set('mysqli.default_pw',   MYSQL_WACHTWOORD);
}


//Name: Nkamp
//Date: 10-08-2012
//Desc: added voor fileupload.

$Mysqli = new mysqli(MYSQL_SERVER, MYSQL_GEBRUIKERSNAAM, MYSQL_WACHTWOORD, MYSQL_DATABASENAAM);
    
if(mysqli_connect_errno())
{


    echo 'Fout bij verbinding: '.$Mysqli->error;

}


try {
    $db_Con = new PDO('mysql:host='.MYSQL_SERVER.';dbname='.MYSQL_DATABASENAAM, MYSQL_GEBRUIKERSNAAM, MYSQL_WACHTWOORD);
    $db_Con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
    echo '<pre>';
    echo 'Regelnummer: '.$e->getLine().'<br>';
    echo 'Bestand: '.$e->getFile().'<br>';
    echo 'Foutmelding: '.$e->getMessage().'<br>';
    echo '</pre>';
}


/**
 * Locale
 *
 * De locale instellen op Nederlands en Nederland
 * en de datum- en tijdzone instellen op Amsterdam.
 *
 * @link http://www.php.net/manual/en/function.setlocale.php
 * @link http://www.php.net/manual/en/timezones.php
 */

setlocale(LC_ALL, 'nl_NL', 'nld_nld', 'Dutch_Netherlands');
date_default_timezone_set('Europe/Amsterdam');
@
ini_set('date.timezone', 'Europe/Amsterdam');
?>


Ik heb er momenteel een connectie voor MySQLi en PDO inzitten. Ik vind het leuk om 'alles' te leren. Bovendien vond ik dit een mooie constructie omdat het zowel op mijn localhost werkt als waar ik de site gehost heb.

Dit wil ik omzetten naar een class zoals het volgende:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
class Database
{
   private static $_dbUser = 'user';
   private static $_dbPass = 'pwd';
   private static $_dbDB = 'dbname';
   private static $_dbHost = 'localhost';
   private static $_connection = NULL;

   /**
    * Constructor
    * prevents new Object creation
    */


   private function __construct(){
   }


   /**
    * Get Database connection
    *
    * @return Mysqli
    */


   public static function getConnection() {
      if (!self::$_connection) {
     self::$_connection = @new mysqli(self::$_dbHost, self::$_dbUser, self::$_dbPass, self::$_dbDB);

         if (self::$_connection -> connect_error) {
            die('Connect Error: ' . self::$_connection->connect_error);
         }
      }

      return self::$_connection;
   }
}

?>


Maar nu weet ik even niet hoe ik define om moet zetten naar private. Ik bedoel ik kan geen if conditie opnemen bij het declareren van de private variablen opnemen. Dit stukje code heb ik bij stackoverflow gevonden en zegt je moet het niet in de constructor opnemen omdat als iemand de classe instantieert meteen ook de variablen mee instantieert.

Alternatieven zijn dan denk ik zowel de variabelen declareren voor localhost en server waar de site gehost wordt en dan de if ($_SERVER['SERVER_ADDR'] == '127.0.0.1') conditie opnemen in de getConnection.

Of kun je het ook met define doen...?

En wat is het meest 'secure'?

Nico
 
PHP hulp

PHP hulp

26/12/2024 09:11:11
 
Erwin H

Erwin H

09/12/2012 23:20:34
Quote Anchor link
Het alternatief voor het definieren van een constante met define is een class constant:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
class MyClass{
  const TEST = 'iets';
}

?>

Nadeel hiervan (in jouw geval) is dat je een class constant nooit private kunt maken. Met andere woorden, die zijn altijd door andere classes uit te lezen. In geval van een database password lijkt me dat niet handig.

Maar als ik goed begrijp wat je wilt zou ik het niet met constantes oplossen, maar met private getters. Je maakt er gewoon een methode van binnen de class die het wachtwoord geeft (of een van de andere) en binnen die methode check je op het adres:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
class Database{
  private getPassword(){
    return ($_SERVER['SERVER_ADDR'] == '127.0.0.1')? 'local_password': 'server_password';
  }
}

?>
Gewijzigd op 09/12/2012 23:20:56 door Erwin H
 
Nkamp Kamp van de

nkamp Kamp van de

27/12/2012 23:16:34
Quote Anchor link
Wel een wat late reactie. Het gaat mij mn. om het 'gehele' plaatje. Daarmee bedoel ik dan of ik het vanuit OO oogpunt goed heb opgezet en ook de try-catch. Ik vraag mij bv. af, is de try-catch die ik voor het instantiëren van de class toegepast heb echt noodzakelijk? Binnen de class gebruik ik ook al een try-catch. Ik heb het dus met private vars opgelost maar misschien is dit vanuit OO niet correct. Dit zijn zo van die zaken die ik mij afvraag.

Nico

Dit is mijn class:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
class DB_Con_MySQL_PDO {
    private $loc_server         = 'localhost';
    private $loc_user         = 'user';
    private $loc_password            = 'locpassword';
    private $loc_dbname        = 'database';
    private $ext_server         = 'db_server';
    private $ext_user         = 'user';
    private $ext_password            = 'password';
    private $ext_dbname         = 'db_naam';

    public function __construct() {
    }


    public function getConnect () {
 
        try {
            if ($_SERVER['SERVER_ADDR'] == '127.0.0.1') {
                // Lokale MySQL-databaseserver
               $db_Con = new PDO('mysql:host='.$this->loc_server.';dbname='.$this->loc_dbname, $this->loc_user, $this->loc_password);
                $db_Con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                // Lokaal alle foutmeldingen weergeven
                error_reporting(E_ALL | E_STRICT);
            }
else {
                $db_Con = new PDO('mysql:host='.$this->ext_server.';dbname='.$this->ext_dbname, $this->ext_user, $this->ext_password);
                $db_Con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                // Alle foutmeldingen op de live server uitschakelen
                error_reporting(0);
            }

            
            /**
             * Locale
             *
             * De locale instellen op Nederlands en Nederland
             * en de datum- en tijdzone instellen op Amsterdam.
             *
             * @link http://www.php.net/manual/en/function.setlocale.php
             * @link http://www.php.net/manual/en/timezones.php
             */

            setlocale(LC_ALL, 'nl_NL', 'nld_nld', 'Dutch_Netherlands');
            date_default_timezone_set('Europe/Amsterdam');
            @
ini_set('date.timezone', 'Europe/Amsterdam');
            
            return $db_Con;
            
        }
catch (PDOException $e) {
            echo '<pre>';
            echo "Failed to obtain database handle: ";
            echo 'Regelnummer: '.$e->getLine().'<br>';
            echo 'Bestand: '.$e->getFile().'<br>';
            echo 'Foutmelding: '.$e->getMessage().'<br>';
            echo '</pre>';
            
            exit;
        }

        return false;
    }
}

?>


Vervolgens heb ik het op deze manier aangeroepen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
session_start ();

/** Error reporting */
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);


require_once ('include/DB_Con_MySQL_PDO.php');
try {
    $con     = new DB_Con_MySQL_PDO ();
    $db_Con    = $con->getConnect();
}
catch(Exception $e) {
  
    echo '<pre>';
    echo "Failed to obtain database handle: ";
    echo 'Regelnummer: '.$e->getLine().'<br>';
    echo 'Bestand: '.$e->getFile().'<br>';
    echo 'Foutmelding: '.$e->getMessage().'<br>';
    echo '</pre>';
    //die('Error loading file: '.$e->getMessage());
}

//Nog wat initialisatie code

try {

//allerlei code om Excel in te lezen.
//Sluiten van de verbinding

    $con         = NULL;
    $db_Con        = NULL;
    
}
catch(Exception $e) {
  
    echo '<pre>';
    echo "Failed to obtain database handle: ";
    echo 'Regelnummer: '.$e->getLine().'<br>';
    echo 'Bestand: '.$e->getFile().'<br>';
    echo 'Foutmelding: '.$e->getMessage().'<br>';
    echo '</pre>';
    //die('Error loading file: '.$e->getMessage());
}
?>
 
Erwin H

Erwin H

28/12/2012 00:33:17
Quote Anchor link
Vanuit OO(P) gezien staan er een paar rare dingen in je class. Ten eerste is het van belang dat je afbakent wat het doel van de class is. Wat moet deze class kunnen? Mij lijkt het dat deze class de connectie (configuratie) van de database regelt. Daar hoort dus niet bij het bepalen van de error reporting en de locale settings. Die zou je door andere classes moeten laten bepalen.

Verder zou ik niet in de getConnect() methode bepalen welke gegevens gebruikt moeten worden. Dat zou ik zoals eerder gezegd oplossen in private getters. Daarmee houd je je code schoner en ook makkelijker uitbreidbaar. Wil je om de een of andere reden dezelfde gegevens nog in een andere methode binnen die class gebruiken dan hoef je niet weer na te denken hoe het ook weer zit met die locale of server gegevens. De getter regelt het al voor je. Eigenlijk komt het ook weer neer op het principe van elke class/methode maar 1 functionaliteit laten hebben.

Wat wel goed is, wat mij betreft, is het gebruik van private properties. Wat mij betreft zijn properties altijd private binnen een class.

De try..catch binnen je class is verder niet verkeerd. Exceptions kan je op vele plekken opvangen en vaak zal je zien dat je als je er van boven naar kijkt, je meerdere try..catch blokken om elkaar hebt staan. Dit komt ook omdat je sommige fouten in de class al kunt oplossen, andere niet. In dit geval kan het bijvoorbeeld handig zijn om de foutmelding af te vangen zodat de kale melding waar mogelijk database gegevens in staan niet omhoog komt. In de class kan je dan een zelfgemaakte exception gooien waar geen gevoelige informatie in staat die helemaal naar boven kan doorbubbelen.
Wat ik overigens niet zou doen is in deze class al een echo en exit plaatsen. Het is niet aan deze class om te bepalen wat de gebruiker te zien krijgt bij een fout. Als het goed is ga je deze class in meerdere applicaties gebruiken en daar weet je nu nog helemaal niets van. Laat die applicaties regelen wat er op het scherm komt, dat is niet de taak van deze class.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

28/12/2012 01:04:03
Quote Anchor link
Even een reactie op het verhaal van Erwin,

properties zijn niet altijd private in een class. vaak zijn ze ook protected zodat als je later een andere class maakt die de methods en properties erft de nieuwe methods nog bij de orginele properties kunnen.

ik stel voor zo min mogelijk try en catch te gebruiken. je code wordt er wat mij betreft niet leesbaarder van en de foutmeldingen evenmin.
 
Erwin H

Erwin H

28/12/2012 10:19:47
Quote Anchor link
Er zijn veel verschillende meningen over private en protected properties (en sommige vinden zelfs public properties geen probleem). De reden waarom ik alleen private gebruik is omdat dat het veel makkelijker maakt om je class op latere momenten nog aan te passen als het nodig zou zijn. Bij protected properties heb je altijd de mogelijkheid dat een afgeleide class die properties direct aanspreekt. Verander je de werking dan van de je class en verwijder je bijvoorbeeld het property, dan werkt die afgeleide class niet meer. Echter, als het property private is met een protected of public getter, dan kan je de interne werking veranderen, zonder dat de afgeleide class daar nadelen van ondervind. Dat is het hele idee nu juist van OOP en classes gebruiken. Protected properties (en zeker public) passen daar wat mij betreft niet in.
Maar het is een mening. Bepaal zelf welke je het liefste gebruikt.

Wat betreft try..catch blokken vind ik de opmerking van Frank echter wel echt verkeerd. 'Zo min mogelijk' vind ik een zeer zwak argument. Het gaat niet om hoe vaak je het gebruikt, maar of je het op de juiste plekken gebruikt. Daar waar je kan verwachten dat er onverwachte foutmeldingen komen (ja, dat is een paradox) is het verstandig om try..catch blokken te gebruiken. Leesbaarheid kan je makkelijk goed houden door je functies klein te houden (zoals uberahupt verstandig is). Waar het om gaat is dat een class alle foutmeldingen afvangt en afhandelt die het kan afhandelen en dat je niet de verkeerde meldingen op het scherm krijgt. Als je daar 10 try..catch blokken voor nodig hebt in deze class, dan heb je er 10 nodig. Er minder van maken om de leesbaarheid te verbeteren is dan een slechte stap.
 
Wouter J

Wouter J

28/12/2012 10:51:28
Quote Anchor link
Ik was vroeger ook voor protected properties, maar sinds een jaar houd ik een erg strict private beleid aan in mijn code. De enige functies die bij mijn properties mogen komen zijn de getters en setters, niks anders. Als ik bijv. hasRole() method maak dan gebruikt die weer een getRoles() method om alle roles op te vragen en kijkt vervolgens of de role daarin zit.

Fabien, een sterk aanhanger van protected, heeft ooit en leuk stukje geschreven waarom ze in Symfony2 over zijn gegaan op private: http://fabien.potencier.org/article/47/pragmatism-over-theory-protected-vs-private
 
Frank Nietbelangrijk

Frank Nietbelangrijk

28/12/2012 11:49:32
Quote Anchor link
!@#%&,

Het lijkt mij dat ik er verschrikkelijk aan zou moeten wennen om alles op private te hebben staan, maar ik neem jullie adviezen wel ter harte.

Wouter, ik ben straks een paar weekjes vrij en wil dan mijn tijd - wanneer ik zin heb- gebruiken om me eens in Symfony2 te verdiepen. Heb je nog tips behalve de cookbook?

Alvast bedankt
 
Moose -

Moose -

28/12/2012 12:20:52
 
Frank Nietbelangrijk

Frank Nietbelangrijk

28/12/2012 12:30:50
Quote Anchor link
thanks, maar dat gaat niet over Symfony of wel?
 
Wouter J

Wouter J

28/12/2012 14:10:09
Quote Anchor link
Frank, om dit topic niet volledig te kapen heb ik even blog artikel aangemaakt daarover: http://wouterj.nl/php/hoe-leer-ik-symfony2/620/
 
Frank Nietbelangrijk

Frank Nietbelangrijk

28/12/2012 14:26:07
Quote Anchor link
super Wouter, heel erg bedankt :-)
 
Nkamp Kamp van de

nkamp Kamp van de

29/12/2012 11:16:02
Quote Anchor link
Ok, bedankt allemaal voor je reacties.

Nu ik jullie opmerkingen lees volledig terecht en ik begrijp het ook want ik zeg zelf altijd "de naam van de functie (class) moet de lading van de functie (class) dekken. En dat doet het in mijn geval niet meer.

Dus ik splitst het op in een class DB_con_PDO en een class config.inc.php bijvoorbeeld.

Ik weet wat getters/setters zijn, dat ken ik wel. Ik begrijp ook het deel private/protected.

Maar dan?
Ga je dan waar je je verbinding nodig hebt 4x met een getter de private:
- usernaam ophalen
- wachtwoord
- databasenaam
- server

Vervolgens roep je de method getconnection aan?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

$db_con
= new db_Con;

if ($_SERVER['SERVER_ADDR'] == '127.0.0.1') {
$user_db_con = get('loc_user');
$databasenaam    = get('loc_databasenaam);
etc.

} else {
$user_db_con = get('
ext_user');
$databasenaam = get('
ext_databasenaam);
etc.
}

$con     = new DB_Con_MySQL_PDO ();
$db_Con  = $con->getConnect($user_db_con, $databasenaam, $..., $....);
?>


Dit is syntactisch nog niet helemaal correct want je hebt daarvoor volgens mij de __Get(..., maar het gaat mij nu even om het idee.

Ok als dit het is dan begrijp ik het wel, maar het komt bij mij een beetje als overdone over. Waarom? Je gaat dan eerst 4x de getter aanroepen en vervolgens nog een keer de get_Connect, terwijl je dat ook in één keer zou kunnen afhandelen.

Anderzijds zou je in de class alleen de properties kunnen plaatsen met een get/setter. En vervolgens in de method/functie waar je deze aanroept ook de verbinding kunnen maken...
 
Erwin H

Erwin H

29/12/2012 11:30:28
Quote Anchor link
De __get magic method kan je gebruiken, maar is in dit geval niet nodig. Je hebt er maar een paar, die ook nog eens duidelijk gedefinieerd zijn. Dan is het veel verstandiger om gewoon de getters uit te schrijven en dus getUsername() en getPassword() te maken.

Wat betreft het overbodige, dat zie ik niet. Of je getters maakt, of direct properties zou aanroepen, die 4 calls moet je toch maken. Eventueel kan je het versimpelen door het in 1 getter om te zetten die een array teruggeeft met alle vier de waardes, maar ook dat lijkt me in dit geval het geheel niet duidelijker maken. Doe je dat dan maak je de afhankelijkheid tussen de twee classes namelijk groter. De DB class moet dan opeens weten hoe die array eruitziet.
 
Nkamp Kamp van de

nkamp Kamp van de

29/12/2012 12:10:40
Quote Anchor link
Nee, wat ik bedoel met 4x aanroepen is dat ik mijn oorspronkelijke versie de class instantieer en de method get_connect aanroepen die dan ook gelijk alles afhandeld.

Met getters/setters dus de OO manier moet ik
- de class instantieeren
- 4x getter aanroepen voor de gegevens ophalen of 1x en dan een array laten retouneren
- en vervolgens nog een een keer de get_Connect method aanroepen.

Gevoelsmatig wil ik die laatste 2 stappen bij elkaar indrukken en in één keer laten uitvoeren. Maar als dit geen goed OO is moet ik dit dus niet doen en het zo opsplitsen.
 
Erwin H

Erwin H

29/12/2012 12:49:24
Quote Anchor link
Ik weet niet of ik helemaal begrijp wat je nu bedoelt, maar die laatste twee in 1 keer doe is natuurlijk mogelijk. Ine je db class:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$this
->connect( $config->getUsername(), $config->getPassword(), etc.. );
?>

Je hoeft in elk geval niet alles eerst in een variabele te stoppen.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.