I have the following database class. My thinking was that this will check for an existing instance of the class and return that rather than create a new database connection.
When I run the code it creates a connection. When I refresh the page another connection is created (checked MySQL connections).
Is my thinking incorrect? Fairly new to using OOP so apologies for the newbie question!
Any help or pointers in the right direction would be appreciated.
Many thanks.
<?php
class Db
{
private $_connection;
private static $_instance;
private $_host = 'localhost';
private $_username = 'root';
private $_password = 'password';
private $_database = 'test';
public static function getInstance()
{
if (!self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
private function __construct()
{
try {
$this->_connection = new PDO("mysql:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
echo 'Connected to database';
} catch (PDOException $e) {
echo $e->getMessage();
}
}
private function __clone()
{
}
public function getConnection()
{
return $this->_connection;
}
}
$db = Db::getInstance();
PHP is a "shared nothing" environment. Each request handled by a PHP application is isolated from all other requests either as a separate thread or a separate process depending on the server api (SAPI) being used. The class you have designed is a singleton but it is isolated to a single request-response cycle. This means that if you call Db::getInstance() 10 times during a single request you will get 10 references to the same object, but a single call in a separate request will create and return a distinct object.
You can use some type of connection pooling, either on the server or application side, to reduce the number of concurrent connections made to your backend database server. PHP's PDO abstraction enables application side connection pooling via the PDO::ATTR_PERSISTENT connection driver option. These pooled connections are cached in the PHP parent process rather than the worker thread/process that handles a request and subsequently reused. The exact number of connections that will be opened and how they are shared is variable depending on your SAPI and underlying database type.
When utilizing PHP for your server side language, understanding what happens in the background is probably a good thing.
PHP initiates the connection for you when you run that code. It does not persist the connection past the page load.
On each page load new connections will be opened so you can continue to make your requests and perform your tasks.
Consider what would happen if it did. You close the page and go to sleep and the server sits with an open connection to the database forever. You get a few visitors and then you hit your connection limit and get a too many connections error.
There are probably some references to cite, but I really can't find many as this is more of a logical problem then a coding problem.
Each time you refresh your page, you are instantiating a brand new Db object, and assigning it to a brand new variable called $db, so you get connections each time. I also think you may be overcomplicating your Db class.
When I reate db class to wrap PDO or mysqli, the idea is to create a db object, that when instantiated would include a database connection as one of it's attributes. To accomplish that, I'd rewrite your class a bit. Something like this would be all you need to create Db object with a private connection that can be used by any range of other methods you wish to add to the class... Say, a method to issue a query,
class Db
{
private $_connection;
private $_host = 'localhost';
private $_username = 'root';
private $_password = 'flindersbeast';
private $_database = 'flinders';
public function __construct()
{
try {
$this->_connection = new PDO("mysql:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
echo 'Connected to database';
} catch (PDOException $e) {
echo $e->getMessage();
}
}
// Other methods here will use $this->_connection to do a variety of things.
public function example()
{
// Do stuff - as needed you can pass $this->_connection to PDO
}
}
$db = new Db;
Good luck!
Related
I've been working on a small project using PHP and MySQL. I've read a lot around about best practices on managing a connection and so on.
I've also implemented (following some posts found around) a singleton class to manage MySQL connections.
require_once 'config.inc.php';
class DbConn {
private static $instance;
private $dbConn;
private function __construct() {}
/**
*
* #return DbConn
*/
private static function getInstance(){
if (self::$instance == null){
$className = __CLASS__;
self::$instance = new $className;
}
return self::$instance;
}
/**
*
* #return DbConn
*/
private static function initConnection(){
$db = self::getInstance();
$connConf = getConfigData();
$db->dbConn = new mysqli($connConf['db_host'], $connConf['db_user'], $connConf['db_pwd'],$connConf['db_name']);
$db->dbConn->set_charset('utf8');
return $db;
}
/**
* #return mysqli
*/
public static function getDbConn() {
try {
$db = self::initConnection();
return $db->dbConn;
} catch (Exception $ex) {
echo "I was unable to open a connection to the database. " . $ex->getMessage();
return null;
}
}
}
But... If my website has like 10K visitors contemporaneously and I'm calling every time my singleton object, should I expect to have performance issues? I meant, shouldn't I have a kind of pool of connections instead of a singleton?
Using singletons in PHP is considered bad practice. From my experience the most problematic issue with them are unit tests. It is hard to ensure that two tests are independent when testing singletons.
I would delegate the responsibility for the constraint "only one instance should exists" to the code which creates the Db object.
Also for me it looks like there is a misunderstanding in how Singletons work in PHP in contrast to other languages: If you have 10.000 concurrent requests for example, then each request runs in a separate PHP process or thread, meaning they will all have their own instance of the "singleton", there is no sharing of this object for more than a single request (when running PHP in common web backend scenarios)
There is no "connection pooling" in PHP, but you can use mysqli persistent connections for mysql. It can be achieved by passing the p: in front of the hostname when creating mysqli. This might help here, but handle it with care (meaning read the documentation first)
However, just for theory, a singleton in PHP must be aware of the fact that someone could use clone. Meaning in your case it would be possible to do that:
$db = DB::getInstance();
$db2 = clone $db;
To avoid that you can implement the __clone() method like this:
public function __clone() {
throw new Exception("Can't clone a singleton");
}
I'm using PDO now and I have a number of classes.
Every time I use a class, I don't always use its database-related functions. Sometimes I keep using a class until at the end I might do some work with the database, like save this object to DB.
So I'm currently doing something like this:
class Something
{
protected $pdo;
function connect()
{
$this->pdo = new PDO( "mysql:host=".zConfig::read('hostname').";dbname=".zConfig::read('database'), zConfig::read('username'), zConfig::read('password'));
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
/* lots of functions doing lots of non-DB things */
function saveToDB()
{ $this->connect();
$this->pdo->prepare("Some SQL that saves some stuff");
// now do some DB-related pdo work
}
}
My question is - is this reasonable? Is this the way a lot of you code?
As I see it, there are 3 options:
The way I'm doing it - connecting to the database only in those
functions that are database related. But these means each time I run a DB-related function.
Open a connection in the constructor, in this case I only open it once, but also end up opening it even when I don't need it, so I feel like sometimes I'll be creating
connections for nothing.
On the other hand, I could use a singleton database class like this:
PDO Connections - max connections
I do have up to three related objects on a page, and sometimes I do and sometimes I don't need to connect to the DB more than once on a page. which design is safer?
You should use DI, in your class to instantiate a connection, when your object is defined ex:
class foo{
public $conn;
function __construct($conn){
$this->conn = $conn;
}
function doSomething(){
}
}
Now, if you find yourself, not wanting to instanciate a connection, whenever you
are on a page/work that does not need database connection, and significantly slows your page, while trying to connect, use the PDO attribute
ATT_PERSISTENT property like:
$conn = new PDO('mysql:host=localhost;dbname=xxx', 'xxx', 'xxx',
array( PDO::ATTR_PERSISTENT => true )
);
$object = new foo($conn);
Simply, once, you open a page, and connection is establish the ATTR_PERSISTENT method will store that connection, pretty much like sessions work, and will keep feeding your page, and helping you from creating a new connection to your db, every time you refresh a page, or go on to another page. Try, it.. and you'll see how faster your pages will load.
You can just use lazy way.
protected $pdo;
function connect()
{
if ($this->pdo === null)
{
$this->pdo = new PDO( "mysql:host=".zConfig::read('hostname').";dbname=".zConfig::read('database'), zConfig::read('username'), zConfig::read('password'));
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
Check this question.
I'm pretty new to both PDO and OOP. I'm trying to write a class that connects to a database and updates inserts and modifies it. I have several questions:
Is it good practices to connect to the database in the constructor?
Should the one class be updating, inserting, modifying and connecting or should it be split up into several classes?
Why is runQuery not working? I assume its because $pdo is defined in a different scope. How would I get this working?
If the class is include at the top of every page does that mean it will reconnect to the database every time a new page is loaded and will that cause security issues?
Apologies for the overload of questions. Thanks in advance for any answers.
<?php
class Login{
private $_username;
private $_password;
private $_host;
private $_database;
private $_driver;
//Connect to the database
function __construct($configFile){
$connectionDetails = parse_ini_file($configFile);
$this->_username = $connectionDetails['username'];
$this->_password = $connectionDetails['password'];
$this->_host = $connectionDetails['host'];
$this->_database = $connectionDetails['database'];
$this->_driver = $connectionDetails['driver'];
$pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
}
public function loginAllowed($user, $pw){
$sth = $pdo->setFetchMode(PDO::FETCH_ASSOC);
print_r($sth);
}
public function runQuery($query, $params){
$sth = $this->pdo->prepare($query);
$sth->execute($params);
}
}
Because $pdo is a local variable in your constructor and your method loginAllowed. You should make it an instance variable (private $pdo) so you can call it through $this->pdo. I also suggest to use type hinting here, give the PDO class as a parameter in the constructor.
Example
<?php
class Login {
private $pdo;
// Your other instance variables
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
// Your other methods
}
$pdo = new PDO("...");
$login = new Login($pdo);
You shouldn't bother your class with reading settings and initialising your database connection (definitely read about separation of concerns), keep it out of your class. Just give the PDO object as a parameter (I used type hinting, that way you are forced to provide an object of the PDO type). Another advantage is that you can now make sure you have only one active database connection (you can manage this in your code base), creating multiple connections is unnecessary and definitely unwanted (performance wise).
Also use require_once to include your class definition. Otherwise you will get many errors about redeclaring (and you'd want to avoid that).
Connect to the db wherever you find it most convenient. Just try to make sure there's only ONE connection. More connections to the same db is a waste of time and resources.
The class you refer to is called a model in the MVC architecture. It usually does all the operations on a given table. I see nothing wrong in using a single class for all your needs - as long as the code is readable and maintainable.
It's not working because $pdo is a local variable. In the ctor, instantiate $this->pdo instead.
Including a class is not equivalent to instantiating it. A new instance will make another connection. Including it multiple times will only give you a multiple declaration error :). Use require_once instead. If you wish to use the instance in multiple files, I strongly suggest you do a quick search regarding the Singleton pattern. Using a singleton object will ensure you always have only one instance of your model object.
Don't bother with all the random stuff, just replacethis in your construct:
$pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
with
$this->pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
and reference it as $this->pdo from now on. As simple as that!!
1) Is it good practices to connect to the database in the constructor?
No good.just connect befor query
if($this->pdo == null) {
$this->pdo = new PDO("....");
}
2) Should the one class be updating, inserting, modifying and connecting or should it be split up into several classes?
Add methods for class
3) Why is runQuery not working? I assume its because $pdo is defined in a different scope. How would I get this working?
use $this->pdo instead
4) If the class is include at the top of every page does that mean it will reconnect to the database every time a new page is loaded and will that cause security issues?
use static $pdo
then self::$pdo would be the only one connector
if(self::$pdo == null) {
self::$pdo = new PDO("....");
}
I am making my first steps in the OOP world - please bear with me.
I know that having many ongoing mySQL connections open at the same time can be fatal for performance, so it should be a good idea to make a database class that takes this into account.
Is $this->session->write(...); going to result in a new mySQL connection being opened each time?
Or is that up to the "persistent connection" feature in mySQL?
Here's the code:
abstract class database {
function __construct() {
//mysql_connect()
}
}
class session extends database {
function write () {
// mysql_query(--.)
}
}
Is session handler some kind of specialized type of database? It is not, so don't use inheritance (a is a relationship). Session handler uses database so you should use composition (a has a relationship):
class Session {
protected $db;
public function __construct(DB $db) {
$this->db = $db;
}
public function write() {
$this->db->query(...);
}
}
$db = new DB(...);
$session = new Session($db);
Also, don't use mysql_*() functions. Use much more powerful PDO.
Returning to your question... mysql_connect() will be executed every time you create a new Database object. However in this case Session is an object of type Database so every time you write new Database() or new Session() the constructor is invoked, therefore mysql_connect() is invoked as well.
PS. mysql_connect() function won't create a new connection if specified connection already exists. Check 4th argument of this function to learn more.
mysql_query will create a new connection only if no previous mysql connection has been made. Otherwise, it will either use the connection you specify or the last connection opened with mysql_connect. http://php.net/manual/en/function.mysql-query.php
Why not
class database {
function __construct() {
//mysql_connect()
}
function write() {
//query the DB
}
}
I'm not sure of the syntax, I don't do OOP PHP. Anyway, in your structure above a new connection would be opened for each "session" instance so assuming you only create one instance of "session" you won't be openeing loads of database connections.
Below is my DB connection class. The problem is that when I try to access the CloseConnection function from my code, it gives error: "Unknown MySQL localhost". I use "dbconnection::CloseConnection" through my other code files. It is successfully opening the connection, but giving error in "$conn".
final class dbconnection
{
private $conn;
//Opens connection for a MySQL DB
public static function OpenConnection()
{
require("../Config/dbconfig.php");
$conn = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
mysql_select_db('MyDB');
}
//Closes connection for a MySQL DB
public static function CloseConnection()
{
mysql_close($conn);
}
}
Below is a method in another PHP file from where I access the above functions:
public static function InsertRecord($inQuery)
{
dbconnection::OpenConnection();
$resultSet = mysql_query($inQuery);
dbconnection::CloseConnection();
return $resultSet;
}
When I remove the line "dbconnection::CloseConnection()", it works fine. I also want to know whether it is a good practice to immediately close the connection as the DB task is finished, or should I keep it open till the use closes the browser?
Try:
class dbconnection {
private static $conn;
public static function OpenConnection() {
require("../Config/dbconfig.php");
self::$conn = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
mysql_select_db('MyDB');
}
public static function CloseConnection() {
mysql_close(self::$conn);
}
}
What you're doing is trying to access the member variable $conn but you're doing it incorrectly so you're simply creating a new (local) variable to use. That doesn't matter on open (the reference is simply discarded) but on close you're not dealing with a resource reference anymore.
Secondly, your functions are static but your member variable isn't. These are the two methods you use for accessing member variables:
class A {
private $a;
private static $b;
public static function foo() {
$this->a = 3; // instance member
self::$b = 4; // static member
}
}
Edit: regarding the last function, it works when you remove the call to CloseConnection() because it is no longer trying to access a database connection via the local variable $conn (which will cause an error).
No it isn't good practice to close a database connection immediately. The most common practice in PHP is simply to open a connection at the top of your script and then do nothing more. When the script exits it will close. Some people open connections on demand, meaning it won't try to create one until it needs one. This is an acceptable optimization (from the point of view of not adding unnecessary complexity). Generally the connection will never be explicitly closed. It will be closed implicitly when the script ends.
Long-lived scripts may want to take a different approach just so they don't unnecessarily hold open connections for extended periods.
You may at some point want to use persistent connections instead.
The above method is simple enough and sufficient enough for some pretty large sites. As a general rule, don't try to optimize this stuff and introduce unneeded complexity until you actually have a problem that you need to do something about.