i have a master database that has all the other database names, when a user logs in i find the appropraite database name on this master database and then use that name to connect the user to the system.What i do is, after getting the database name i save it as a session and pass that session to the database name for my other database conncetion. This is how i connect the user to the system
class DataDB extends mysqli {
// single instance of self shared among all instances
private static $instance = null;
// db connection config vars
private $dbName = $_SESSION['dname'];
private $dbHost = "localhost";
//This method must be static, and must return an instance of the object if the object
//does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
so far its refusing to work am getting this error Parse error: syntax error, unexpected '$_SESSION' (T_VARIABLE). Also is there a better way to do this without session
Change the way you assign the private property by setting it in the __construct() method of your class.
Although I do not recommend this, use a config file, you could use this Symphony component though. Here you have an example.
Also a quick tutorial for using composer might aid you
EDIT:
private function __construct() {
$this->dbName = $_SESSION['dname'];
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName); //or pass it directly
}
Related
I am using below code for database connection
class Database extends PDO{
function __construct(){
try {
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
} catch(PDOException $e){
Logger::newMessage($e);
logger::customErrorMsg();
}
}
}
every thing like login , fetching data was working fine . Now suddenly I am having a exception error message
Message: SQLSTATE[08004] [1040] Too many connections
Code: 1040
How to fix this error ?
I have a model class there I am creating new database.
class Model {
protected $_db;
public function __construct(){
//connect to PDO here.
$this->_db = new Database();
}
}
and every model I make , I am extending from model class.
Because your Model class instantiates a new Database object in its constructor, each time you instantiate a Model (or any class extending it), you are in effect opening a new database connection. If you create several Model objects, each then has its own independent database connection, which is uncommon, usually unnecessary, not a good use of resources, but also actively harmful as it has used up all the server's available connections.
For example, looping to create an array of Model objects:
// If a loop creates an array of Model objects
while ($row = $something->fetch()) {
$models[] = new Model();
}
// each object in $models has an independent database connection
// the number of connections now in use by MySQL is now == count($models)
Use dependency injection:
The solution is to use dependency injection and pass the Database object into the Model::__construct() rather than allow it to instantiate its own.
class Model {
protected $_db;
// Accept Database as a parameter
public function __construct(Database $db) {
// Assign the property, do not instantiate a new Database object
$this->_db = $db;
}
}
To use it then, the controlling code (the code which will instantiate your models) should itself call new Database() only once. That object created by the controlling code must then be passed to the constructors of all models.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
For the use case where you actually need a different independent database connection for a model, you can hand it a different one. In particular, this is useful for testing. You can substitute a test database object, or a mock object.
// Instantiate one Database
$db = new Database();
$another_db = new Database();
// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);
Persistent connections:
As mentioned in the comments, using a persistent connection is possibly a solution, but not the solution I would recommend. PDO will attempt to reuse an existing connection with the same credentials (as all yours will have), but you don't necessarily want the connection to be cached across script execution. If you did decide to do it this way, you need to pass the attribute to the Database constructor.
try {
// Set ATTR_PERSISTENT in the constructor:
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS, array(PDO::ATTR_PERSISTENT => true));
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
The relevant documentation is here: http://php.net/manual/en/pdo.connections.php#example-950
Singleton solution:
Using a singleton pattern (also not recommended), you could at least reduce this to a search/replace in the model code. The Database class needs a static property to keep a connection for itself. Models then call Database::getInstance() instead of new Database() to retrieve the connection. You would need to do a search and replace in the Model code to substitute Database::getInstance().
Although it works well and isn't difficult to implement, in your case it would make testing a little more difficult since you would have to replace the entire Database class with a testing class of the same name. You can't easily substitute a test class on an instance by instance basis.
Apply singleton pattern to Database:
class Database extends PDO{
// Private $connection property, static
private static $connection;
// Normally a singleton would necessitate a private constructor
// but you can't make this private while the PDO
// base class exposes it as public
public function __construct(){
try {
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
} catch(PDOException $e){
Logger::newMessage($e);
logger::customErrorMsg();
}
}
// public getInstance() returns existing or creates new connection
public static function getInstance() {
// Create the connection if not already created
if (self::$connection == null) {
self::$connection = new self();
}
// And return a reference to that connection
return self::$connection;
}
}
Now you would need to change only the Model code to use Database::getInstance():
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}
I am looking into oop to enhance my web dev knowledge. At the moment i am having a bit of an issue. I have created a Database class that contains all the queries etc. ( fetch, count, etc. ) This just allows the queries or updates to take up less space in the other classes etc. The issue i am having is passing this class along and making it globally accessible. I have used
global $db;
within a class function but i read that it is bad practice to use that. I also do not want to pass the $db variable as a parameter if i did i would have to change a lot of my current classes and it would just be easier if i can make $db globally available in a "good" practice way.
I can provide my Database class if necessary it is just a simple class with the variable that initiates the connection through construct.
( Second Question )
I was also reading about the singleton instance function, before implementing i read that it was also considered bad practice. Is there something that should take its place?
( I decided to place the class below )
class Database {
private $host = 'localhost';
private $user = 'xxx';
private $pass = 'xxxx';
private $dbname = 'xxxxx';
private $dbh;
private $error;
public function __construct(){
// Set DSN
$dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
// Set options
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING,
PDO::ATTR_EMULATE_PREPARES => false
);
// Create PDO Instance
$this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
}
public function fetch($sql, $param = "") {
$this->stmt = $this->dbh->prepare($sql);
if (empty($param)) {
$this->stmt->execute();
} else {
$this->stmt->execute($param);
}
return $this->stmt->fetch();
}
}
$db = new Database();
An example of what i am attempting to accomplish is as follows
( User Profile Page )
class User {
function set_user($input) {
if (is_numeric($input)) {
$this->user = $input;
} else {
$user = $db->fetch("SELECT userid FROM users WHERE url=:url", array(':url' => $input));
$this->user = $user['userid'];
}
}
}
AN issue with your approach is not the global var, but that the DB connection is permanently open. It is not always good. This is kind of service object and it is not partiularily bad to have it globally visible.
If you don't want it global and want to solve the open connection issue, you can easily close the connection in the destructor, remove the global var and create/use/delete the DB wherever required.
Another approach would be not to use singleton, but so called service class. Make DB class not instanciable, but rather define service methods (all static) - open, close, execute, or whatever. Than the DB clients should not create DB object, but only access the static methods. This approach fits the reality very nice, as DB-access is seen as a service.
I'm new. Below is the beginning of an attempt to interface with a database. Please let me know if the syntax is not correct, it seems to work on my localhost.
I think I could have typed class Database extends Mysqli, right? which would then have made the methods of Mysqli directly accessible to Database rather than through an instance created in the class itself. Would that have been preferable to what I have done?
class Database {
#The variable that stores the database handle
public $db;
#The Database objects's datbase parameters
public $host;
public $user;
public $password;
public $database;
#creates a Database object with the required databases details
public function __construct($host, $user, $password, $database) {
$this->host = $host;
$this->user = $user;
$this->password = $password;
$this->database = $database;
}
#Stores the database handle as a var $db of the Database instance
public function connect() {
if ($this->db = new Mysqli($this->host, $this->user, $this->password, $this->database)) {
if ($this->db->connect_errno) {
echo "No connection could be made <br/>";
} else {
echo "database succesfully connected <br/>";
}
}
}
}
If your class Database represents the database handle, then it should not have it public:
#The variable that stores the database handle
public $db;
Otherwise you would not encapsulate that detail and therefore you wouldn't need your class at all.
Next to that, when you start to write classes, echo does not belong in there:
if ($this->db = new Mysqli($this->host, $this->user, $this->password, $this->database)) {
if ($this->db->connect_errno) {
echo "No connection could be made <br/>";
} else {
echo "database succesfully connected <br/>";
}
}
Because classes consists of methods returning via their return value and not via standard output. Instead you want to throw an exception here. Which is also a feature of Mysqli already, therefore, you don't need to write that error handling code your own to get started:
Turning query errors to Exceptions in MySQLi
After getting these more or less obvious ones out of the way, you're asking yourself whether or not you should inherit mysqli instead of aggregating it.
I actually can not tell you. So far the code you've shared just shows standard functionality of a mysqli therefore I would suggest to drop that class completely as the code looks superfluous. So I would say: neither. I see no reason for your Database class as you just could use mysqli instead.
I am using PHP's PDO to access my MySQL DB. I typically create a singleton class for my connection. I would like to set a MySQL session variable when initiating the connection, and later on as well. See below for my failed attempts to set MySession1 and MySession2. How can I do this? Thanks
EDIT. Just found out that it works if you only use one #. I was originally using two at-signs ## which I thought the documentation at http://dev.mysql.com/doc/refman/5.0/en/using-system-variables.html required. How am I misinterpreting the documentation?
class db {
private static $instance = NULL;
private function __construct() {} //Make private
private function __clone(){} //Make private
public static function db() //Get instance of DB
{
if (!self::$instance)
{
self::$instance = new PDO("mysql:host=localhost;dbname=myDB", 'myUsername', 'myPassword');
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$instance->exec('SET #MySession1=123');
}
return self::$instance;
}
}
db::db()->exec('SET #MySession2=321');
$stmt=db::db()->query('SELECT #MySession1 AS MySession1, #MySession2 AS MySession2');
$rs=$stmt->fetch(PDO::FETCH_ASSOC);
echo("MySession1={$rs['MySession1']} MySession2={$rs['MySession2']}");
There is a difference between server variables and user defined variables. See http://dev.mysql.com/doc/refman/5.0/en/user-variables.html for the description of user defined variables.
So recently I've really started to use php actively, and I need some insights on different ways to use database connections.
At first I just used the simple mysql_connect():
<?php
$connection = mysql_connect(DB_HOST, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_DB, $connection);
?>
After a while I created a database class which I started to include and initialize in every file - something like this:
<?php
class MySQL_DB {
var $connection;
function MySQL_DB(){
$this->connection = mysql_connect(DB_HOST, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_DB, $this->connection);
}
function query($q){
$res = mysql_query($q, $this->connection) or die(mysql_error());
return $res;
}
}
$database = New MySQL_DB;
?>
And this is what I'm using at the time - and it's working fine - but there are always ways to improve.
So my question to you is how do you manage your database connections?
Do you use classes?
What does your classes contain (just
the connection or even functions?)
What practices do you recommend?
I recommend to use PDO. Don't reinvent the weel. It's a nice OO-interface to many database engines.
Additionally I create a small function which just inititializes PDO object. So all connection settings can be changed in one place.
Your current approach is pretty standard, and works well. I used it for a long time. It's true that modules like PDO provide base functionality like this now, which is very nice as well and can get you away from problems with home-brew code.
However, I've taken the connection management one step further. If you get into a complex application, you might get into a situation where you have multiple databases, or heavy database use. Including a single database connection file and having a global $database variable becomes unwieldy for multiple databases, and it's unnecessary for application requests that might not need a database connection. Remember, connecting to the database is expensive.
What I've done is create a singleton DatabaseManager class that handles the database object for me, and makes sure multiple connections to a given DB don't get instantiated. Instead of initializing a new database object at the top of your app, you simply call on the DatabaseManager every time you need the object.
$db = DatabaseManager::getDatabase();
Here's an example class that I had whipped up for a CodeIgniter project. You can see in the getDatabase() function it simply loads CodeIgniter's default database object, which you would substitute for your own class (and run the connection routine for it) if you weren't using CI. This is a pretty simplistic management class, and could be extended to manage multiple connections to different databases fairly easily.
<?php
/**
* Implements the Singleton pattern to prevent multiple instantiations and connections
* to the application database.
*
*/
class Database_manager
{
private static $instance;
public $db;
/**
* Constructor function is declared private to prevent instantiation.
*
*/
protected function __construct()
{
parent::__construct();
}
/**
* Returns an instance of a Database_manager.
*
* #return object Database_manager object
*/
public static function getInstance()
{
if (self::$instance == null) {
$className = __CLASS__;
self::$instance = new $className();
}
return self::$instance;
}
public static function getDatabase()
{
$instance = self::getInstance();
if ($instance->db == null) {
//utilize CodeIgniter's database loader
$instance->db = $instance->load->database('',true);
if (! is_object($instance->db)) throw new Exception("Could not load database.");
}
return $instance->db;
}
}
Perhaps the most common advantage I get out of using this style of connection management is when I have to take down an application for database maintenance. By not instantiating a database connection until I need it, I can easily put up a "maintenance in progress" message on a site (short circuiting normal MVC dispatching), and not worry about requests to the application opening a DB connection while maintenance is in progress.
Usage of classes are the way to go to increase customized re-usability.
Bring in all generic implementations into the class. You are on the right track.
This website has the following clean approach.
This website link is no longer present. Archive Link.
class connection {
// Possible Modules are as follows:
// DBX_MYSQL, DBX_ODBC, DBX_PGSQL, DBX_MSSQL, DBX_FBSQL, DBX_SYBASECT, DBX_OCI8, DBX_SQLITE
private $module = DBX_MYSQL;
private $host = "localhost";
private $database = "test";
private $username = "testuser";
private $password = "testpass";
private $link;
private $result;
public $sql;
function __construct($database=""){
if (!empty($database)){ $this->database = $database; }
$this->link = dbx_connect($this->module,$this->host,$this->database,$this->username,$this->password);
return $this->link; // returns false if connection could not be made.
}
function query($sql){
if (!empty($sql)){
$this->sql = $sql;
$this->result = dbx_query($this->link,$sql,DBX_RESULT_UNBUFFERED);
return $this->result;
}else{
return false;
}
}
function fetch($result=""){
if (empty($result)){ $result = $this->result; }
return dbx_fetch_row($result);
}
function __destruct(){
dbx_close($this->link);
}
}
In your database manager example, you did not define a parent for your class.
Therefore, invoking parent::__constructor() yields an exception,
and also, you cannot use the load property of code ignitor.
Which class did you use as an extension for your DatabaseManager?
Since i do not know where you placed your databasemanager code, nor which class you used as its parent, i circumvented the exceptions by making the getDatabase() method receive an input parameter which i called $loader.
Normally, this $loader object will be the model class requiring access to a database.
public static function getDatabase($loader)
{
$instance = self::getInstance();
if ($instance->db == null) {
//utilize CodeIgniter's database loader
$instance->db = $loader->load->database('default',true);
if (! is_object($instance->db)) throw new Exception("Could not load database.");
}
return $instance->db;
}
Best regards.