Od czasu do czasu pojawiają się pytania dotyczące łączenia się z bazą danych.
Większość odpowiedzi nie jest tak, jak to robię, lub po prostu mogę nie uzyskać poprawnych odpowiedzi. Tak czy inaczej; Nigdy o tym nie myślałem, ponieważ sposób, w jaki to robię, działa na mnie.
Ale oto szalona myśl; Może robię to wszystko źle, a jeśli tak jest; Naprawdę chciałbym wiedzieć, jak poprawnie połączyć się z bazą danych MySQL za pomocą PHP i PDO i uczynić ją łatwo dostępną.
Oto jak to robię:
Po pierwsze, oto moja struktura plików (rozebrana) :
public_html/
* index.php
* initialize/
-- load.initialize.php
-- configure.php
-- sessions.php
index.php
Na samej górze mam require('initialize/load.initialize.php');
.
load.initialize.php
# site configurations
require('configure.php');
# connect to database
require('root/somewhere/connect.php'); // this file is placed outside of public_html for better security.
# include classes
foreach (glob('assets/classes/*.class.php') as $class_filename){
include($class_filename);
}
# include functions
foreach (glob('assets/functions/*.func.php') as $func_filename){
include($func_filename);
}
# handle sessions
require('sessions.php');
Wiem, że istnieje lepszy lub bardziej poprawny sposób włączania zajęć, ale nie pamiętam, co to było. Nie miałem jeszcze czasu, żeby się temu przyjrzeć, ale myślę, że to było coś z tym autoload
. coś w tym stylu...
configure.php
Tutaj po prostu nadpisuję niektóre właściwości php.ini i wykonuję inną globalną konfigurację witryny
connect.php
Umieściłem połączenie w klasie, aby inne klasy mogły ją rozszerzyć ...
class connect_pdo
{
protected $dbh;
public function __construct()
{
try {
$db_host = ' '; // hostname
$db_name = ' '; // databasename
$db_user = ' '; // username
$user_pw = ' '; // password
$con = new PDO('mysql:host='.$db_host.'; dbname='.$db_name, $db_user, $user_pw);
$con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$con->exec("SET CHARACTER SET utf8"); // return all sql requests as UTF-8
}
catch (PDOException $err) {
echo "harmless error message if the connection fails";
$err->getMessage() . "<br/>";
file_put_contents('PDOErrors.txt',$err, FILE_APPEND); // write some details to an error-log outside public_html
die(); // terminate connection
}
}
public function dbh()
{
return $this->dbh;
}
}
# put database handler into a var for easier access
$con = new connect_pdo();
$con = $con->dbh();
//
Wierzę, że jest miejsce na ogromne ulepszenia, odkąd niedawno zacząłem uczyć się OOP i używać PDO zamiast mysql.
Właśnie skorzystałem z kilku samouczków dla początkujących i wypróbowałem różne rzeczy ...
session.php
Oprócz obsługi zwykłych sesji, inicjalizuję również niektóre klasy w sesję taką jak ta:
if (!isset($_SESSION['sqlQuery'])){
session_start();
$_SESSION['sqlQuery'] = new sqlQuery();
}
W ten sposób ta klasa jest dostępna w każdym miejscu. To może nie być dobra praktyka (?) ... W
każdym razie to podejście pozwala mi robić z każdego miejsca:
echo $_SESSION['sqlQuery']->getAreaName('county',9); // outputs: Aust-Agder (the county name with that id in the database)
Wewnątrz mojej sqlQuery
- klasy , która jest extends
moją connect_pdo
- klasą , mam funkcję publiczną o nazwie, getAreaName
która obsługuje żądanie do mojej bazy danych.
Myślę, że całkiem nieźle.
Działa jak urok.
Tak to właśnie robię.
Poza tym za każdym razem, gdy potrzebuję pobrać coś z mojej bazy danych spoza klasy, po prostu robię coś podobnego do tego:
$id = 123;
$sql = 'SELECT whatever FROM MyTable WHERE id = :id';
$qry = $con->prepare($sql);
$qry -> bindParam(':id', $id, PDO::PARAM_INT);
$qry -> execute();
$get = $qry->fetch(PDO::FETCH_ASSOC);
Ponieważ umieściłem połączenie w zmiennej wewnątrz connect_pdo.php , po prostu nawiązałem do tego i jestem gotowy . To działa. Otrzymuję oczekiwane rezultaty ...
Ale niezależnie od tego; Byłbym wdzięczny, gdybyście mogli mi powiedzieć, że jestem daleko. Co powinienem zrobić zamiast tego, obszary, które mógłbym lub powinienem zmienić w celu poprawy itp.
Chętnie się uczę ...
Odpowiedzi:
Cel
Jak widzę, twój cel w tym przypadku jest dwojaki:
Rozwiązanie
Zalecałbym użycie zarówno funkcji anonimowej, jak i wzorca fabrycznego do obsługi połączenia PDO. Jego użycie wyglądałoby następująco:
$provider = function() { $instance = new PDO('mysql:......;charset=utf8', 'username', 'password'); $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $instance; }; $factory = new StructureFactory( $provider );
Następnie w innym pliku lub niżej w tym samym pliku:
$something = $factory->create('Something'); $foobar = $factory->create('Foobar');
Sama fabryka powinna wyglądać mniej więcej tak:
class StructureFactory { protected $provider = null; protected $connection = null; public function __construct( callable $provider ) { $this->provider = $provider; } public function create( $name) { if ( $this->connection === null ) { $this->connection = call_user_func( $this->provider ); } return new $name( $this->connection ); } }
W ten sposób uzyskasz scentralizowaną strukturę, która zapewnia, że połączenie jest tworzone tylko wtedy, gdy jest to wymagane. Ułatwiłoby to również znacznie proces testowania jednostkowego i konserwacji.
Dostawca w tym przypadku zostałby znaleziony gdzieś na etapie ładowania początkowego. Takie podejście dałoby również jasne miejsce, w którym należy zdefiniować konfigurację używaną do łączenia się z bazą danych.
Należy pamiętać, że jest to niezwykle uproszczony przykład . Możesz także skorzystać z obejrzenia dwóch następujących filmów:
Również gorąco polecam przeczytanie odpowiedniego samouczka na temat korzystania z PDO (w Internecie jest dziennik złych tutoriali).
źródło
mysql_*
do PDO. Następnie możesz wrócić i spojrzeć na to rozwiązanie, które jest skierowane do tych, którzy już używają PDO, ale potrzebują sposobu na współdzielenie połączenia DB między wieloma klasami.Sugerowałbym, aby nie używać
$_SESSION
globalnego dostępu do połączenia DB.Możesz zrobić jedną z kilku rzeczy (w kolejności od najgorszych do najlepszych ):
$dbh
za pomocąglobal $dbh
funkcji i klasUżyj pojedynczego rejestru i uzyskaj do niego dostęp globalnie, na przykład:
Wprowadź procedurę obsługi bazy danych do klas, które jej potrzebują, na przykład:
class MyClass { public function __construct($dbh) { /* ... */ } }
Gorąco polecam ten ostatni. Jest znany jako iniekcja zależności (DI), inwersja kontroli (IoC) lub po prostu zasada Hollywood (nie dzwoń do nas, zadzwonimy do ciebie).
Jest jednak trochę bardziej zaawansowany i wymaga więcej „okablowania” bez szkieletu. Tak więc, jeśli wstrzykiwanie zależności jest dla ciebie zbyt skomplikowane, użyj pojedynczego rejestru zamiast wielu zmiennych globalnych.
źródło
sqlQuery
ustawię moją -class na sesję, ponieważ się rozszerzaconnect_pdo
?Niedawno sam doszedłem do podobnej odpowiedzi / pytania. Oto co zrobiłem, na wypadek gdyby ktoś był zainteresowany:
<?php namespace Library; // Wrapper for \PDO. It only creates the rather expensive instance when needed. // Use it exactly as you'd use the normal PDO object, except for the creation. // In that case simply do "new \Library\PDO($args);" with the normal args class PDO { // The actual instance of PDO private $db; public function __construct() { $this->args = func_get_args(); } public function __call($method, $args) { if (empty($this->db)) { $Ref = new \ReflectionClass('\PDO'); $this->db = $Ref->newInstanceArgs($this->args); } return call_user_func_array(array($this->db, $method), $args); } }
Aby to nazwać, wystarczy zmodyfikować tę linię:
$DB = new \Library\PDO(/* normal arguments */);
I podpowiedzi typu, jeśli używasz go do (\ Library \ PDO $ DB).
Jest bardzo podobna zarówno do zaakceptowanej odpowiedzi, jak i do Twojej; jednak ma to znaczącą zaletę. Rozważ ten kod:
$DB = new \Library\PDO( /* args */ ); $STH = $DB->prepare("SELECT * FROM users WHERE user = ?"); $STH->execute(array(25)); $User = $STH->fetch();
Chociaż może wyglądać jak normalne PDO (zmienia się
\Library\
tylko przez to ), w rzeczywistości nie inicjalizuje obiektu, dopóki nie wywołasz pierwszej metody, cokolwiek to jest. To sprawia, że jest bardziej zoptymalizowany, ponieważ tworzenie obiektów PDO jest nieco kosztowne. To przezroczysta klasa lub coś, co nazywa się Ghost , forma Lazy Loading . Możesz traktować $ DB jako normalną instancję PDO, przekazując ją sobie, wykonując te same operacje itp.źródło
$dsn = 'mysql:host=your_host_name;dbname=your_db_name_here'; // define host name and database name $username = 'you'; // define the username $pwd='your_password'; // password try { $db = new PDO($dsn, $username, $pwd); } catch (PDOException $e) { $error_message = $e->getMessage(); echo "this is displayed because an error was found"; exit(); }
źródło