I was reading this SO question:
PHP - multiple different databases dependency injected class
Top answer. I understand the concept behind using an Interface here, but I don't know how to use it. Here is what the top answer said, sorry if I'm not supposed to copy it here:
You should create an interface first for all the DB operations.
interface IDatabase
{
function connect();
function query();
...
}
Then have different driver classes implementing this interface
class MySQLDB implements IDatabase
{
}
class PGSQLDB implements IDatabase
{
}
This way you can easily use dependency injection.
class Test
{
private $db;
function __construct(IDatabase $db)
{
$this->db = $db;
}
}
You can call it as:
$mysqldb = new MySQLDB();
$test = new Test($mysqldb);
or
$pgsqldb = new PGSQLDB();
$test = new Test($pgsqldb);
What I don't understand is how to complete it in the class test and what I am passing to test. Where is my connection information going? I was hoping someone would help me complete this for a mysql connection or maybe pdo.
Your connection info would go in the MySQLDB class, so you could have something like this:
class MySQLDB implements IDatabase
{
private $pdo; // Holds the PDO object for our connection
// Or you can remove the parameters and hard code them if you want
public function __construct( $username, $password, $database) {
$this->pdo = new PDO( '...'); // Here is where you connect to the DB
}
public function query( $sql) {
return $this->pdo->query( $sql); // Or use prepared statments
}
}
Then you instantiate it outside of the class:
$db = new MySQLDB( 'user', 'pass', 'db');
And pass that $db object to one of your classes expecting an IDatabase:
$obj = new Test( $db); // Dependency Injection, woo hoo!
You can also look into having the MySQLDB class extending the PDO class, but that is your design choice.
Finally, you might be better off just sticking with PDO and getting rid of all this, as it is a great abstraction layer that works with many different databases.
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();
}
}
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.
I'm very new to oop in php, so far i'm using multiple classes that I made in one php file, such as:
class Style {
//stuff
}
class User {
//other stuff
}
And many more, yet i'm having an issue on how to connect to mysql within these classes, if I use $db = new Mysqli(); how will I be able to make queries from inside classes? what if i'm trying to make my own connector class like so:
class Connection extends mysqli {
public function __construct($host, $user, $pass, $db) {
parent::__construct($host, $user, $pass, $db);
if (mysqli_connect_error()) {
die('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
}
}
How can I be able to make queries from within different classes? Or what's a better way of using oop in php correctly? with multiple classes to organize different parts of code?
Any help or tips will be appreciated, thanks. What about using PDO? does that make everything easier?
class Style {
public function __construct($conn) {
$this->conn = $conn;
//use $this->conn in the class
}
}
$db = new Mysqli();
$style = new Style($db);
I think the first example is the preferred method, however you could create a simple registry class and use that to store a $db object etc.
If possible I would probably use PDO but that doesn't solve this issue.
Since you are extending the mysqli class you will have access to the functions as you would if you instantiated that class by itself (so long as those functions aren't private). Some folks though (including myself) will instantiate the DB connection in their own custom class with a database connection, then inject that class into classes that need it.
class MyDatabase {
private $this->dbi;
public function __construct() {}
public function connectDB($host, $user, $pass, $db)) {
//You can do this in the constructor too, doesn't have to be its own function
$this->dbi = new mysqli($host, $user, $pass, $db);
}
public function getDBI() {
return $this->dbi;
}
}
You can add all the functions you want to your own class (or an extended class), you can also have any class that needs a database extend your DB class. But that isn't really preferred (each class will have a different db class/connection). The easiest is probably to import your DB connection into your class. Either through the constructor or another function;
class MyClass {
private $this->database;
public function __construct($db) {
$this->database = $db->getDBI();
}
public function query($q) {
//Of course, clean your data first, and best practices use prepared statements
$result = $this->database->query($q);
return $result;
}
}
Then make your database connection and inject it into your class.
$db = new MyDatabase();
$db->connectDB('localhost', 'username', 'password', 'mydb');
$class = new MyClass($db);
$resultSet = $class->query("SELECT * FROM MyTable"); //Obviously anything the user could add here is to not be trusted.
using PDO will give you a lot of functions and flexebilty and it has many drivers built-in.
to make what you are trying to do here is a sample :
STEP 1 :
Make a Main class that will handle your database :
class app extends PDO {
protected $database_hostname = "localhost";
protected $database_username = "root";
protected $database_password = "";
protected $database_name = "testdb";
protected $database_type = "mysqli";
public function __construct() {
try {
parent::__construct($this->database_type . ':host=' . $this->database_hostname . ';dbname=' . $this->database_name, $this->database_username, $this->database_password, array(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION));
} catch (PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
}
}
STEP 2 :
then you need to initilze a globale variable as your Database :
$db= new app() ;
STEP 3 :
include a local variable to handle database in the other classes :
class User{
public $db ;
}
STEP 4 :
in the constructor of the other classes ( user for exemple ) you need to pass the local variable by reference to the globale variable :
class User{
public $db ;
public function __construct(){
global $db;
$this->db =& $db;
}
}
STEP 5 :
then if you want to execute a request from inside a class you do it by the local variable :
$this->db->query("SELECT * FROM user");
and from the outside just by using : $db->query("SELECT * FROM user");
I hope that helped !
Sorry for the stupid question am a newbie to oop in php...i have a proble wiriting a mysqli class thet returns a connection handler that enable me the connection handler in other classes/methods. i run a small procedural blog n wanted to convert to oop.
heres a my working code example. please refactor for me where necessary. Thank in advance.
$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
public function getConfig($id, $db_link) // thanks cbuckley
{
$db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
i have defined the constants already and the connection is successful but the select is not working. on the index page this goes
include('inc/dbc.php');
$db = new MyDB();
echo $db->getConfig(1, $db_link);
any help is appreciated
Your question is not very specific, and I have the feeling you're not really aware what your concrete problems are. You've already accept an answer that gives you some code but puts you in the wrong direction as it does not solve your underlying problem and wastes code.
The first thing you should know if you want to make use and benefit of the object oriented interface of PHP's mysqli extension is, that the Mysqli class represents the database connection (the "link" as it was named for a procedural approach) already:
require('inc/dbc.php');
$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
That's already it. Sure you might want to use some error handling here:
if ($dbConnection->connect_error)
{
throw new Exception(
sprintf('(#%d) %s', $dbConnection->connect_errorno,
$dbConnection->connect_error)
);
}
Throwing exception instead of let's say die('message') is done, because you can easily create an exception handler so that you can display a more useful response to the user from within a central place instead of handling each exceptional error-case where it appears (actually at the place where die would be).
You can also log and mail the backtrace so you can fix things more easily. Naturally you do not need to use exceptions, however the rule of thumb is to use die only in scripts you throw away in let's say a week and it does not work well with object oriented design.
As you will need this code anyway in all places where you will need your database connection, you can create your own connection object to bring those parts together as they belong together:
class DatabaseException extends Exception
{
}
class DatabaseConnection extends Mysqli
{
public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {
parent::__construct($host, $user, $password, $database, $port, $socket);
$this->throwConnectionExceptionOnConnectionError();
}
private function throwConnectionExceptionOnConnectionError() {
if (!$this->connect_error) return;
$message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);
throw new DatabaseException($message);
}
}
The usage is actually pretty straight forward and very much the same, only the name of the class varies and it's definition needs to be loaded:
require('inc/dbc.php');
require('inc/database.php');
$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
As written, the connection object already represents your database connection. So every part in your application that needs it, has to ask for it. Let's review your example function:
function getOption($id, $db_link)
{
// $db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
I renamed the function and I commented the first line, even this might be what you want. Actually, if that function would be part of the DatabaseConnection object, it could work like this:
class DatabaseConnection extends Mysqli
{
...
public function getOption($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
As this example demonstrates, the database connection is already there. However, this is not advisable. Imagine you not only have options but this and that and such and what not more. You would create one function after the other all in one class. Well for a little application that might even so work right, but imagine more and more. You would get one very large class that is responsible for many things. So it would be bad to do this, even if you can use $this already to prepare the statement.
Also take note that you should prepare statements. This has been answered here numerous times, if you're not used to it, read about it, it's worth the lines. There are better ways to not repeat code (DRY: Don't repeat yourself) while stepping into object oriented (you should even already do this with procedural).
So as to have this all in one class would be a problem, you instead put it in a class of it's own:
class DatabaseModelBase
{
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
protected function prepare($query) {
$connection = $this->connection;
$statement = $connection->prepare($query);
if (!$statement) {
throw new DatabaseException(
sprintf('(%s) %s', $connection->error, $connection->errno)
);
}
return $statement;
}
}
class Option extends DatabaseModelBase
{
public function find($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
}
This has some extended error handling again, because most often mistakes are made in the SQL query. And as you can see the individual function to fetch some specific data is placed in it's own class. You can use such classes to group the fetching and updating for specific datatypes.
Usage in full:
$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$option = new Option($dbConnection);
$optionValue = $option->find(1);
echo $optionValue; # value for option with ID1
The names of the Option object probably is not well, I tried to keep the example lightweight but also offer some separation. For other scenarious you might want to prefer some different kind how to access the db connection, because it is injected into Option via it's constructor, Option does not deal any longer with the details how the database connection is being created.
For example you can make the database connection object more smart only to connect to the database the first time prepare or query is actually used with it. So that requests to your website that do not need a database connection would not needlessly connect to the database.
You find more examples in other questions and you might want to learn about dependency injection. Also you always want to keep things apart from each other, so you have some objects that are only lightly connected to each other.
How to successfully rewrite old mysql-php code with deprecated mysql_* functions?
Dependency Injection simple implementation
I would suggest moving the connect to the database also inside the class:
class myDB extends mysqli
{
private $link;
public function Connect()
{
$this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
}
public function getConfig($id) // thanks cbuckley
{
$res = mysqli_query($this->link,"SELECT * from config where id='$id'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
And use it like this:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
I recommend you to Wrap the mysqli class in a new Class instead extending it:
For those Classes, where you need the Configuration, just include the Configuration with Dependency Injection. This brings you the Benefit, that the Code, where you need the Configuration, don't need to know about the Way, Configuration get its values.
If you later decide to parse Configuration from a iniFile, you only need to change the Configuration-Class or even better, write a new Class which implements ConfigurationInterface and inject the new ConfigurationClass.
class Configuration implements ConfigurationInterface{
private $mysqli;
public function construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
}
public function get($key)
{
// You should escape this query to prevent SQL-injection
$res = $this->mysqli->query("SELECT * from config where id='$key'");
$row = $res>fetch_array();
return $row['option'];
}
}
interface ConfigurationInterface {
public get($key);
}
Use it like this:
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
I'm quite new to PDO and also OOP with PHP in general so please be nice :) Basically I'm trying to make a connection object based on PDO so that I can have one connection that I call throughout my site.
I need some prepared statements that simply look up different results based on an ID I pass through using the same db object that I'm trying to create below.
How do I make and access the db class I set below and then use functions within it to extract the relevant info I need? Any examples would be great so I can get an idea of the best practices etc.
Many thanks in advance.
class db {
private static $connection;
private function __construct(){}
private function __clone(){}
private static function connect($db_server="localhost", $db_user="user", $db_pass="password") {
if(!$this->connection){
try{
$this->connection = new PDO($db_server, $db_user, $db_pass);
} catch (PDOException $e) {
$this->connection = null;
die($e->getMessage());
}
}
return $this->connection;
}
}
$dbh = new db::connect();
$stmt = $dbh->prepare("SELECT * FROM questions where id = ?");
if($stmt->execute(array($_REQUEST['testid']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
You could begin by not ever using Singleton pattern again. It (and static classes in general) is bad for all the same reasons why global variables in procedural programming are bad.
That said ... Instead of trying to enforce the uniqueness of the connection object, you should be just making sure that you using the same connection all over the place.
Here's an example of what i mean by that:
class Foo
{
protected $connection = null;
public function __construct( PDO $connection )
{
$this->connection = $connection;
}
}
class Bar
{
// all the same as in Foo
}
$connection = new PDO('sqlite::memory');
$foo = new Foo( $connection );
$bar = new Bar( $connection );
At this point both $foo and $bar objects will have access to the same PDO instance. If you have an object that needs access to database, then you just provide it with a connection in the constructor.
There are two videos you might want to watch (slides will contain Java code, but you should have no troble understanding it):
Global State and Singletons
Don't Look For Things!
Persistent connections are built in:
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
PDO::ATTR_PERSISTENT => true
));
See Example #4 Persistent connections