Is extending classes good practice? - php

I have a PDO connection in my database class and recently I have been using this as an extension for other classes i.e. class Users extends Database this allows me to always keep a Database connection without having to have a function in my Users class.
However somebody pointed out that I shouldn't be doing this as its bad practice, why exactly is this bad practice? And how can I connect to my database class in my user class without extending?
Currently I have the call to the database inside my viewall() function I tried to put this in a __construct() function however it insisted on having parameters
I've tried the below code however I get the error message as follows:
Fatal error: Call to undefined method Database::prepare() in E:\xampp\htdocs\attendance\class.Register.php on line 13
Any ideas on how I can call on my database?
This is my code:
class.Connect.php
<?php
// Database connection PDO
class Database {
public function __construct() {
// Connection information
$host = 'localhost';
$dbname = 'attendance';
$user = 'root';
$pass = '';
// Attempt DB connection
try
{
$this->pdo = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//echo 'Successfully connected to the database!';
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
public function __destruct()
{
// Disconnect from DB
$this->pdo = null;
//echo 'Successfully disconnected from the database!';
}
}
?>
class.Register.php
<?php
require 'class.Connect.php';
class Register {
public function viewall() {
$pdo = new Database();
$stmt = $pdo->prepare('SELECT * FROM users');
$stmt->execute();
$stmt->fetch();
}
}
$run = new Register();
$run->viewall();
?>

Simple rule of thumb: if a class extends another, then that class is that parent class (only slightly altered or extended). You can pass this child class instead of the parent class. Example:
class Foo { }
class Bar extends Foo { }
function baz(Foo $foo) { }
baz(new Bar);
This works, baz() expects a Foo but also accepts a Bar, because Bar is a Foo.
Now, is your Users a Database? No. Your users are not a database. Your users use a database. If at all, you should use composition:
class User {
protected $database;
public function __construct(Database $database) {
$this->database = $database;
}
}
A class should be what its responsibilities are. The responsibility of a user management class is to manage user data. Part of that may involve talking to a database, but that doesn't mean the user management class is a database. If User extends Database, that means it can do everything the Database class can do (and more). That means you could use the User class everywhere instead of the Database class, and that doesn't make any sense. Keep responsibilities separate.
Now, it's still debatable whether that is the right structure or not, but it goes into the right direction. But you may really want to have a User class, which represents one user. You then have a UserManager or UserORM or UserStorage or whatever, which is concerned with retrieving and storing User objects in a database. This class in turn uses a Database to do just that. That keeps responsibilities clear and separated. The User class represents user data, the Database class interacts with the database, the UserORM/Manager/whatever in the middle negotiates between the two.

There may be several ways to connect to a database such that you have a connection everywhere in your application. For a good practice, you can do it easily by using another class which can handle your datbase operations and you extend all your classes which require db operations from that class.
First change your Database class a little and pass the arguments for database connection as below :
<?php
// Database connection PDO
class Database {
public function __construct($host, $dbname, $user, $pass) {
// Connection information
// Attempt DB connection
try
{
$this->pdo = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//echo 'Successfully connected to the database!';
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
public function __destruct()
{
// Disconnect from DB
$this->pdo = null;
//echo 'Successfully disconnected from the database!';
}
}
?>
Now create another class lets call it ObjectModel as below
class ObjectModel
{
protected $db
public function __construct()
{
$this->db = new Database($host, $dbname, $user, $pass) //ofcourse you can get the db connections details and database name from a config file
}
// you can have more db operations functions like insert, update, delete etc
}
SO the ObjectModel class will be handling all your CRUDs and other db operations and running queries also. Now if you want to use the $db object, you can use it directly in the ObjectModel class and also in child classes of OBjectModel as below:
class Users extends ObjectModel
{
public function getUsers()
{
//$this->db-> whatever operation you want to do you can do it using this db object
}
}
Remember that the ObjectModel has an object of the Database class called $db, so if your Database class is using PDO, then your ObjectModel $db object will have all those operations ie, using PDO.
I hope this will help for you also, as i am using such ObjectModel class for my classes and it saves me a lot of time to write codes again and again :) .
Happy Coding ;)

Is extending classes good practice?
Well, yes, if you do it right and for the right reason.
The concept of inheritance (class extensions) in object-oriented programming is working like the same as if you had those objects in real world.
In real world when you use the world Car, then by convention you usually mean all the cars and you consider common attributes in it, for example, wheels, engine, steering, throttle, brake etc.
but there are some cars that have those attributes and some additional too, for example a Fire Truck Car also has some extra attributes as a ladder attached, some tubes for water throwing etc.
The same could be considered for the "behavior" of some objects, for example, a car can move, and by that we mean you have wheels rotation on the road in order to move (modeled by Car move method).
Also, a firetruck may have an extended behavior, for example can move up and down the ladder it has. This can be modelled by having the method moveLadder() in the FireTruckCar class.
If you wanted to represent these concepts in PHP classes (OOP), you could do:
class Car {
protected $wheels;
protected $engine;
//Rest attributes of Car.
public function __construct($wheels, $engine) {
$this->wheels = $wheels;
$this->engine = $engine;
//Initialize more attributes.
}
function move(){
$this->wheels->rotate();
}
//.....
}
class FireTruckCar extends car{
//Additional Attributes.
//The attributes of Car class belong to this
//one too and are accessible as private.
protected $ladder;
protected $tubes;
public function __construct($wheels, $engine, $ladder, $tubes) {
//Call the parent constructor, to initialize parent attributes
parent::__construct($wheels, $engine);
$this->ladder = $ladder;
$this->tubes = $tubes;
}
function moveLadder($direction){
$this->ladder->move($direction);
}
//...
}
Of course, there are many additional concepts in inheritance and generally OOP such as method overloading/overriding, abstract classed etc., but I am not goind to explain about them here as the point will be missed.I suggest you search for Object Oriented Programming Principles though and learn about them well.

Related

How to fix Message: SQLSTATE[08004] [1040] Too many connections

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();
}
}

Singleton v Single Instance DB Connection in PHP

I'm moving onto teaching myself OOP in PHP.
I'm creating a couple of little web apps and have followed a lot of tutorials that either create the database (using PDO) via a Singleton, or via passing the global around. I've read that these are pretty much the same thing and are both to be avoided like the plague.
So I've watched the Google Tech Talks on clean code, and read almost every SO article on dependency injection and the like. I have a couple of questions.
The clean code videos suggest you shouldn't do 'work' in your constructors. Is this 'work' in reference to business logic. Ie. If my class's job is to create another object, is that an OK kind of 'work'?
For example, in trying to conform to single repsonibility classes I created three.
Class DB - which actually connects to the database.
Class DBFactory - which creates the DB object which connects to the database.
Class DBInstance - which returns a single instance of the DBFactory created PDO object.
Please note that I'm trying to create a single instance, without creating a Singleton pattern.
So I try and pass my dependencies for each class up the chain. I find myself in a position where I have to create all of the objects (from DB down) so I can inject the dependencies. For some reason I thought it would work the other way, I'd create the first object, which would create the second for me etc. I'm clearly missing something?
Hopefully this helps others as well - there seems to be a myriad of questions relating to this stuff and databases but very little good examples.
(I should mention this does work, I do get a list of hotel names out of the database!)
TestCode.php
include './classes/DB.php';
include './classes/DBFactory.php';
include './classes/DBInstance.php';
include './classes/Location.php';
$db = new DB;
$dbfactory = new DBFactory($db);
$dbinstance = new DBInstance($dbfactory);
$dbh = $dbinstance->getDbInstance();
//Example business logic
$location_names = Location::getLocationNames($dbh);
print_r($location_names);
Class DB.php:
class DB {
private $_dbhost = 'myhost';
private $_dbname = 'myname';
private $_dbuser = 'myuser';
private $_dbpass = 'mypass';
private $_error;
public function connect() {
try {
return new PDO("mysql:host=$this->_dbhost;dbname=$this->_dbname",
$this->_dbuser, $this->_dbpass);
}
catch (PDOException $e) {
$this->_error = 'Error! ' . $e->getMessage() . '<br />';
die();
}
}
public function getError() {
if (isset($this->_error)) {
return $this->_error;
}
}
}
Class DBFactory.php
class DBFactory {
private $_dbh;
public function __construct(DB $db) {
$this->_dbh = $db;
}
public function Create() {
return $this->_dbh->Connect();
}
}
Class DBInstance.php
class DBInstance {
private static $_dbinstance;
public function __construct(DBFactory $dbfactory) {
if (!isset(self::$_dbinstance)) {
self::$_dbinstance = $dbfactory->Create();
}
}
public function getDbInstance() {
return self::$_dbinstance;
}
}
Your code seems to do what you want it to.. but maybe we can use less object instantiation using inheritance and maybe we can avoid static properties in instanciated classes.
Also in regard to using a pattern of dependency injection that is able to handle multiple connections, but support using a single instance of it. exemple first, classes after
$params = array
('host'=>'localhost',
'db'=>'ice',
'user'=>'kopitar',
'pass'=>'topnet',
'charset'=>'utf8'); // passing the charset explicitely is great
$handle = new handle($params);
$db = $handle->getInstance();
we can either pass the $db to our functions
$location_names = Location::getLocationNames($db);
or the whole $handle. as long as $handle is not reconstructed, it will always return the same database connection.
$location_names = Location::getLocationNames($handle);
if I want to reconstruct I need the whole $handle
$handle->__construct(/* params but with another database infos */);
$db2 = $handle->getInstance();
As for the classes, I think we want the params to arrive from the instanciated class, so we can change them later.
class db {
function __construct($params) {
foreach ($params as $param => $value) {
$this->{$param} = $value; // assigns the connections infos
}
}
protected function connect() {
$dsn = 'mysql:host='.$this->host.';dbname='.$this->db.';charset='.$this->charset;
return new PDO($dsn,$this->user,$this->pass);
}
}
the factory creates a connection from params and passes it to something else, good factory
class factory extends db {
protected function create() {
return $this->connect();
}
}
now we want to have our object to keep it's connection as long as we do not rebuild it. so we give it to instance
class instance extends factory {
function instantiate() {
$this->instance = $this->create();
}
}
and last but not least, our handle which returns the instance. it could be in instance class.....................
but I feel like having four and find no real reason not to.
class handle extends instance {
function __construct($params) {
db::__construct($params);
$this->instantiate(); // when we construct a handle, we assign an instance to the instance property
}
function getInstance() {
return $this->instance;
}
}
KISS
Don't make things more complex than they are, of course this is just my opinion, but as I see it you are building a complex solution for a problem that someone else says might exist is some cases.
Php is not multi threaded so there goes one of the biggest arguments overboard. (in very rare-occasions it might be)
I'm using singletons for my database connections for about 15 years now and never ever had a problem with them, I do play around with different connections having one singleton handle several connection instances, but whatever... it works great and everyone that looks at the code.. understands it directly.
I'm not using globals because they can be overwritten and are kind of hard to predict (when it holds the correct object, and when/why they don't)
Use OOP to make your code cleaner, easier to work with and more flexible.
Don't use it to fix problems that aren't there and make your code more complex because others tell you to.
An very simple example of a db-connection singleton class handling several different connections.
class singleton{
private static $_instances=array();
public static function getInstance($connectionName){
if(!isset(self::$_instance[$connectionName]){
self::$_instance[$connectionName]=self::_getConnection($connectionName);
}
return self::$_instance[$connectionName];
}
}
just my 2 cents
Why do you have a factory if you have a singleton? This is needless.
This is a never-ending debate, but I'm advocate of do not use singletons for database connections.
As far as in most applications, you have only one data channel, you can consider your database connection unique, but this might not be always true.
In deed, the effort made to create a singleton database connection is even bigger than just create a regular one.
Also, your class DB is not configurable, therefore, you need to change it when your connection parameters change. And I think DB is a very bad name for this.
I'd rather call this Storage and do something like:
inteface Storage {
public function insert($container, array $data);
public function update($container, array $data, $where);
public function delete($container, $where);
public function getAll($container);
public function getOne($identifier);
}
final class PdoStorage implements Storage {
private $dbh;
private $dsn;
private $user;
private $pswd;
public function __construct($dsn, $user, $pswd) {
$this->dsn = $dsn;
$this->user = $user;
$this->pswd = $pswd;
}
// Lazy Initialization
private function connect() {
if ($this->dbh === null)
$this->dbh = new PDO($this->dsn, $this->user, $this->pswd);
}
public function insert($container, array $data) {
$this->connect();
// ... omitted for brevity
}
}
Now, when you need a database storage, you do:
$someObj = new SomeClass(new PdoStorage(...));
Now you might be wondering if you will need to create an PdoStorage for each single object that depends on it.
The answer is: no!
Now you can use a factory to simplify your life.
class SomeFactory {
private $defaultStorage;
public function __construct(Storage $storage) {
$this->defaultStorage = $storage;
}
public function create($type) {
// Somehow fetches the correct class to instantiate and put it into $class variable , for example... and then
return new $class($this->defaultStorage); // Or you'd better do this with reflection
}
}
$factory = new SomeFactory(new PdoStorage(...));
$factory->create('SomeClass');
This way, you can have just one database connector or more if you need.

One connection for ALL ,OOP PHP

struggling to grip the varying levels of variables in OOP PHP. I want to have one connection file which can be accessed from all classes and functions through out my project. I include 'config.php' but the $mysql variable cannot be found. Any help greatly appreciated;
I have a file
config.php
public $mysqli = new mysqli('localhost', 'usernameEG', 'passwordEG', 'databaseEG');
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
and a few class files
class.User.php
<?php
class User {
private $mysqli = null;
function __construct(){
//=========
//include config.php here?
}
function myProfile($Id){
$stmt = $this->mysqli->prepare("SELECT First_Name, Last_Name, Email, DateJoined FROM members WHERE Id = ? ");
$stmt->bind_param('i',$Id);
$stmt->execute();
$stmt->bind_result($fname,$lname,$email,$date);
$stmt->store_result();
$stmt->fetch();
echo "<p>User#: ".$Id."</p>";
echo "<p>First Name: ".$fname."</p>";
echo "<p>Last Name: ".$lname."</p>";
echo "<p>Email: ".$email."</p>";
echo "<p>Date Joined: ".$date."</p>";
$stmt->close();
}
function example(){
EXAMPLE CODE HERE WILL ALSO NEED TO BE ABLE TO USE SAME CONNECTION
}
}
So rather than a singleton approach as hinted at in the other answer. Let me offer you a dependency injection approach. For a lot of experienced developers, dependency injection is a preferred approach, as it allows the class receiving the dependency to have looser coupling to the dependency (for example, you don't need to even know the name of the class for instantiating the dependency like you would with a singleton approach). You just need to know that the dependency being passed meets some interface requirement (i.e. it implements some interface or is a certain type of class).
So that would look more like this:
class User {
protected $mysqli = null;
// other properties
public function __construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
// other constructor operations
}
// other methods
}
So what is happening here? Here you enforce the requirement to pass an object of type mysqli when instantiating this class. This could be a mysqli object or perhaps even your own custom class which extends mysqli, the User class doesn't care, so long as all mysqli class methods are implemented
Usage could be like
require('/path/to/db_config.php'); // an include which creates a mysqli object or provides a factory for one, or whatever
$user = new User($mysqli);
$user->foo(); // do something
Interestingly enough, you might at times see use of singelton pattern along with dependency injection. So say you had a mysqli_singleton_factory class with singleton functionality to provide you the single instantiated mysqli object. The usage might look like this:
require('/path/to/db_config.php'); // an include which provides a singleton
$user = new User(mysqli_singleton_factory::get_instance());
$user->foo(); // do something
$other_class = new other_class_requiring_mysqli(mysqli_singleton_factory::get_instance());
$other_class->bar(); // do something
Here you have both guaranteed that you only have one instantiated mysqli object during script execution AND you have decoupled your User class from having to do any instantiation of the object itself.
For reference, a singleton pattern may look like this:
class mysqli_singleton_factory {
protected static $mysqli = null;
protected function __construct() {
// assume DB connection setting have been pre-defined as constants somewhere
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// make sure connection worked
if($mysqli->connect_error) {
throw new Exception(__METHOD__ . ' at line ' . __LINE__ . ' failed with: ' . $mysqli->connect_error);
}
self::mysqli = $mysqli;
}
public static function get_instance() {
if (false === self::mysqli instanceof mysqli) {
self::__construct();
}
return self::mysqli;
}
}
I've done this a number of times previously and I have found that it is easy to implement "singleton-like" class to serve as a database connector which then can be referenced by any object in the application.
config.php
Config.php is where the credentials are set and the database class is actually constructed.
$dbHost = 'localhost';
$dbUser = 'someUser';
$dbPass = 'somePass';
$dbSchema = 'someSchema';
Database::$db = new MySQLi($dbHost, $dbUser, $dbPass, $dbSchema);
classes.php
classes.php is where my classes are defined, which is kept separate from the rest of the code.
class Database {
public static $db;
}
class User {
...
function example()
{
$stmt = Database::$db->prepare('SELECT TRUE');
...
}
}
index.php
index.php is the entry point for the app, and is used to handle the request and exhibit the desired behavior using the supplied classes.
require_once('classes.php');
require_once('config.php');
/* Application Goes Here */
This ensures that all objects in my project use the same connection, I only have to invoke it once and I don't have to mess about with scope too much.

Inheriting database connection in PHP OOP

My abstract class Database is made for database interaction and any child of this class (UserDatabase, ActionDatabase, EventDatabase) inherits its database connection which is defined as static.
abstract class Database {
public static $connection;
public function __construct( ) {
...
$this->connection = mysql_connect( $host, $username, $password );
}
}
class UserDatabase extends Database {
public function verify( ) {
if ( $this->connection == parent::$connection ) {
print "true";
} else {
print "false";
print "this:" . $this->connection . " parent:" . parent::$connection;
}
}
}
$instance = new UserDatabase( );
$instance->verify( );
// this prints false, as parent::$connection is empty
Does that mean, that my database connection is only set up and stored in memory once and passed on to subclasses as reference without being replicated for each instance?
Is this how you would implement you OOP-correct database interface?
Ignoring your code for a moment and looking only at your description of how this scheme should work... Yes, the database connection would only be set up once for each PHP script and would not be duplicated for each instance.
Whether this is a good idea or not depends on what your subclasses are. Each class should have one responsibility. As long as the subclasses' only responsibility is DB interaction, you're probably fine. (Look at the Repository Pattern for an explanation of how this is commonly done.) If your User class extends Database so that it can store itself, you've crossed a line and are writing classes that will have too many dependencies and responsibilities.
As for your code... Almost every line of your code is wrong. You cannot initialize class variables to the results of a function. Your SQL is wrong. The line $connection ? "connected" : "not connected"; does nothing. Almost none of that should be done in a constructor. Etc.
That pattern is OK if you're doing nothing else with those classes but database interactions.
Otherwise you may be better off with a Database class that's created once that you can "getInstance()" of each time. Singleton Design Pattern.
http://www.tonymarston.net/php-mysql/singleton.html

How do you manage database connections in php?

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.

Categories