db connection voor MySQL via een class
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)
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
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');
?>
/**
* 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)
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
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;
}
}
?>
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
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)
Gewijzigd op 09/12/2012 23:20:56 door Erwin H
Nico
Dit is mijn class:
Code (php)
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
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;
}
}
?>
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)
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
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());
}
?>
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());
}
?>
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.
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.
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.
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
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
http://www.amazon.com/PHP-5-Objects-Patterns-Practice/dp/1590593804 ) boek. Echt heel goed
Dit ( thanks, maar dat gaat niet over Symfony of wel?
super Wouter, heel erg bedankt :-)
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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, $..., $....);
?>
$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...
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.
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.
Je hoeft in elk geval niet alles eerst in een variabele te stoppen.