How to use database connection in other classes - php

PHP programming is pretty new to me - so I hope that I don't ask something stupid. However, I could not find any answer to my problem :-(
I have saved my database connection in a separate .php file. Let's say "connection.inc.php"
connection.inc.php looks as follows:
$host = "name.server.com";
$dbname = "foo";
$user = "bar";
$pass = "PaSW0rd";
try
{
$DBH = new PDO("mysql:host=$host;dbname=$dbname",$user,$pass,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
}
catch(PDOException $e)
{
...
}
In my index.php I would include the connection.inc.php with 'include_once "connection.inc.php"
Additionally, I have a class called house.class.php in which I have a method with an SQL query to my database. I call the method via 'getColor($id, $DBH)' from my index.php
Is there any way to use the method without always putting $DBH into the call?
Thanks for your help!

Let's say you have a class named House with a getColor() method, and in your index.php. You can use the keyword global inside your function/method, but I am strongly against this. Example:
public function getColor(int $id)
{
global $dbh;
//and use it as $dbh
$dbh->prepare(....
}
Or you can inject it in the constructor. Example of how your class will look like
class House
{
private $dbh;
function __construct($dbh)
{
$this->dbh = $dbh;
}
public function getColor($id)
{
//$this refers to current object context
$this->dbh->prepare.....
}
}
And when you instantiate the House object you will pass the $DBH into the constructor. Example for your index.php:
include_once "connection.inc.php";
$house = new House($DBH);
$house->getColor($id);
Although, I suggest that you checkout Domain Driven Design, Factory and Repository pattern, and ORM like Doctrine or Eloquent to get more understanding on how to separate your application/domain logic from the database.

You should get the $DBH from the class itself rather than in the index file. Then you can have that instance of the database connection available to use class wide with other methofs in that class as well without having to re-connect for every function or having to provide every function the connection as an argument.
An example of this would look something like this:
house.class.php
<?php
class House{
private $DBH;
function __construct(){
include_once "connection.inc.php";
$this->DBH = $DBH;
}
function getColor($id){
$this->DBH // <---- use it like this instead of your $DBH old variable.
}
}
?>

class Database
{
private $host = "localhost";
private $dbname = "codeignitor";
private $username = "root";
private $password = "";
public $conn;
public function getConnection()
{
$this->conn = null;
try {
$this->conn = new PDO ("mysql:host=" . $this->host . ";dbname=" . $this->dbname, $this->username, $this->password);
$this->conn->exec("set names utf8");
// echo "MySqlConnected";
} catch(PDOException $exception){
echo "Connection error: " . $exception->getMessage();
}
return $this->conn;
}
}

Related

How to create 2 PDO database connection instances PHP

I currently have a class which creates one database connection, however I would like to create another connection too. I have tried copying the class structure but just renaming the variables and functions however that doesn't work and it seems like it doesn't detect where my new PDO connection is as I get error Uncaught Error: Call to a member function prepare() on null in. What is the best approach to take in my case when creating 2 database connections?
config.php:
<?php
class Database
{
private $host = "localhost";
private $db_name = "database1";
private $username = "root";
private $password = "";
public $conn;
public function dbConnection()
{
$this->conn = null;
try
{
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $exception)
{
echo "Connection error: " . $exception->getMessage();
}
return $this->conn;
}
}
?>
class.user.php:
class USER
{
private $conn;
public function __construct()
{
$database = new Database();
$db = $database->dbConnection();
$this->conn = $db;
}
public function runQuery($sql)
{
$stmt = $this->conn->prepare($sql);
return $stmt;
}
}
You could create your User class and pass the connection to the constructor. This will give you flexibility to swap out the connection.
Regarding your database class, it seems to be a wrapper, to create a PDO connection. You could do away with it, or extend the class with different params.
Perhaps look at dependency injection, and containers. They might help you here.
<?php
class User
{
private $conn;
public function __construct(PDO $conn)
{
$this->conn = $conn;
}
public function runQuery($sql)
{
$stmt = $this->conn->prepare($sql);
return $stmt;
}
}

Return database connection from function

I'm trying to return $db connection from function, so that I could use it in another function. But someone functions don't understand $db variable.
function dbConnection(){
$dbhost = 'localhost';
$dbuser = '...';
$dbpass = '...';
$dbname = '...';
try {
$db = new PDO("mysql:host=$dbhost;dbname=$dbname;charset=UTF8", $dbuser, $dbpass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $db;
} catch (PDOException $e){
echo 'Connection failed: ' . $e->getMessage();
}
}
Then use it in all of my functions.
function getCurrentFile(){
dbConnection();
$stmt = $db->prepare(...);
$stmt->execute();
}
Are there more preferable way to handle db connections? I used to require_once config.php(where is only db connection) file every time, but I don't want to do it anymore.
One of the options is define singletone class providing database object:
// File: DbConection.php
class DbConnection
{
/**
* #var \PDO
*/
private static $pdo;
private function __constructor()
{
}
public static function getInstance()
{
if(null === self::$pdo) {
self::$pdo = new \PDO('....);
}
return $self::pdo;
}
private function __clone()
{
}
private function __wakeup()
{
}
}
If you are using composer tool, add this line to composer.json file:
"autoload": {
"classmap": [
"path_to_your_file/DbConnection.php"
]
},
In your project, on bootstrap include generated by composer vendor/autoload.php file and start using class by:
use DbConnection;
DbConnection::getInstance();
in whole projec.
Write down your db connection code in class and create object to use everywhere else in your system.

How to use PDO connection in other classes?

I think I've a problem in understanding how OOP works. I already changed the code that it works, but it isn't the propper way I think. Following scenario (No, I'm not creating a userlogin by myself, its really just for local dev. to understand OOP better):
I've a database.php file:
class Database {
/* Properties */
private $conn;
private $dsn = 'mysql:dbname=test;host=127.0.0.1';
private $user = 'root';
private $password = '';
/* Creates database connection */
public function __construct() {
try {
$this->conn = new PDO($this->dsn, $this->user, $this->password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "";
die();
}
return $this->conn;
}
}
So in this class I'm creating a database connection and I return the connection (object?)
Then I have a second class, the famous User class (actually I'm not using autoload, but I know about it):
include "database.php";
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct() {
$this->conn = new Database();
}
/* Login a user */
public function login() {
$stmt = $this->conn->prepare("SELECT username, usermail FROM user");
if($stmt->execute()) {
while($rows = $stmt->fetch()) {
$fetch[] = $rows;
}
return $fetch;
}
else {
return false;
}
}
}
So thatare my two classes. Nothing big, as you see. Now, don't get confued about the function name login - Actually I just try to select some usernames and usermails from database and displaying them. I try to achieve this by:
$user = new User();
$list = $user->login();
foreach($list as $test) {
echo $test["username"];
}
And here comes the problem. When I execute this code, I get the following error message:
Uncaught Error: Call to undefined method Database::prepare()
And I'm not sure that I really understand what causes this error.
The code works well when I change the following things:
Change $conn in database.php to public instead of private (I think thats bad...? But when its private, I can only execute querys inside of the Database class, I'm right? So should I put all these querys in the Database class? I think that's bad, because in a big project it will get become really big..)
And the second change I've to do is:
Change $this->conn->prepare to $this->conn->conn->prepare in the user.php file. And here I've really no Idea why.
I mean, in the constructor of the user.php I've a $this->conn = new Database() and since new Database will return me the connection object from DB class, I really don't know why there have to be a second conn->
Do not create classes such as your Database class as it's rather useless. It would make sense to create a database wrapper if it adds some extra functionality to PDO. But given its current code, better to use vanilla PDO instead.
Create a single $db instance from either vanilla PDO or your database class.
Pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new \PDO($dsn, $user, $pass, $opt);
user.php
<?php
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct(\PDO $pdo) {
$this->conn = $pdo;
}
/* List all users */
public function getUsers() {
return $this->conn->query("SELECT username, usermail FROM user")->fetchAll();
}
}
app.php
include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();
foreach($list as $test) {
echo $test["username"],"\n";
}
output:
username_foo
username_bar
username_baz
Check out my (The only proper) PDO tutorial for more PDO details.

Call to a member function prepare() on null OOP

Having trouble understanding classes and inheritance:
core.php:
$servername = "****";
$database = "****";
$username = "****";
$password = "****";
try {
$pdo = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
class Database {
protected $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
}
class User extends Database {
private $ip;
private $sessionId;
public function __construct($ip, $sessionId) {
$this->ip = $ip;
$this->sessionId = $sessionId;
}
public function getSessionInfo () {
$stmt = $this->pdo->prepare(".."); <-- error here
....
}
}
When calling:
require_once 'api/core.php';
$database = new Database($pdo);
$user = new User($_SERVER['REMOTE_ADDR'], $_SESSION['info']['id']);
In this contest $database, and $user variables are not related to each other:
require_once 'api/core.php';
$database = new Database($pdo);
$user = new User($_SERVER['REMOTE_ADDR'], $_SESSION['info']['id']);
Thus, calling prepare() on $user won't work.
You need a mechanism, at least like this , although not a good practice to assign Database to a User:
$user->setDatabase($database);
Instead create a static Database object, initiate it before User initiation, and call it statically within User object, or any other object, make it available for all objects.
A quick fix would look like this, where User doesn't extend Database, because it's wrong. User is not a Database.
$database = new Database();
$user = new User();
$user->setDatabase($database); //sets $db variable inside User
//User.php
namespace MyApp;
class User{
private Database $db;
public function setDatabase($db){
$this->db = $db;
}
public function doSomething(){
$this->db->getPdo()->prepare('..');
}
}
//Database.php
namespace MyApp;
class Database{
private $pdo; //returns PDO object
function __construct(){
//create pdo connection
$this->pdo = ..
}
function getPdo(){
return $this->pdo;
}
}
Database should be injected to objects or used by objects, you shouldn't be extending Database just to have it. If you want to do it properly, in an object-oriented way.
Remember PHP doesn't allow multiple inheritances by extend. Tomorrow, you might want to have a Person class that every User will extend, but since you did it wrong in the beginning, and wasting precious extend on Database, it won't be possible. And by not having a control of how many database instances you have created, you will run into issues. You need to know for sure that you have only a single connection object for one database, if of course the opposite is a must - which in your case I doubt.
Of course this will change if you have multiple database requirements, and more sophisticated app structure.
You are receiving this error because User Instance has pdo empty. try this code
$servername = "****";
$database = "****";
$username = "****";
$password = "****";
try {
$pdo = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
class Database {
protected $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
}
class User extends Database {
private $ip;
private $sessionId;
public function __construct($pdo, $ip, $sessionId) {\
parent::__construct($pdo)
$this->ip = $ip;
$this->sessionId = $sessionId;
}
public function getSessionInfo () {
$stmt = $this->pdo->prepare("..");
....
}
}
then
require_once 'api/core.php';
$user = new User($pdo, $_SERVER['REMOTE_ADDR'], $_SESSION['info']['id']);
hope it helps.

PHP OOP and PDO

My first real foray into using PHP OOP and PDO extensively. I have finally gotten the script to work, but as you notice in order to do it I had to move the PDO connect into the login function - originally it was just in the __construct(). I do not want to have to open a new PDO connect and this is sloppy. How can I maintain the same connection throughout the whole class?
<?php
class user{
public $id;
public $name;
public $email;
private $password;
public function __construct() {
$DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function login($email,$password,$type){
$DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$password_hash = sha1($password);
try{
if ($type != "actives") {
throw new Exception("Type Handling Error");
}
$STH = $DBH->query("SELECT id, email, password FROM $type WHERE email='$email' AND password='$password_hash'");
$STH->setFetchMode(PDO::FETCH_ASSOC);
$row_count = $STH->rowCount();
$row = $STH->fetch();
if($row_count == 1){
session_start();
session_regenerate_id();
$_SESSION['id'] == $row[id];
return true;
}
else{
return false;
}
}
catch (Exception $e) {
echo $e->getMessage();
}
}
public function loggout(){
session_destroy();
setcookie(session_name(), session_id(), 1, '/');
}
Make the database handle a private member within the class:
class user
{
public $id;
public $name;
public $email;
private $password;
private $dbh;
public function __construct(PDO $dbh)
{
$this->dbh = $dbh;
}
public function login($email, $password, $type)
{
$dbh = $this->dbh;
...
}
Usage:
$pdo = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = new User($pdo);
Sooner or later, you may need the PDO connection object somewhere else in your code(outside your user object). Therefore,
I would suggest to use one class which will provide static method as below to get the PDO connection object everywhere you want.
class Database{
private static $datasource='mysql:host=HOST dbname=DB';
private static $username='USER';
private static $password='PASS';
private static $db;
//make the constructor private and empty so that no code will create an object of this class.
private function __construct(){}
//the main public function which will return the required PDO object
public static function getDB(){
if(!isset(self::$db)){
try{
self::$db=new PDO(self::$datasoure,self::$username,self::$password);
}
catch(PDOExceptin $e)
{
$error=$e->getMessage(); //variable $error can be used in the database_error.php file
//display database error file.
include('database_error.php');
exit();
}
}
return self::$db;
}
}
Then you can use the static method like below any time you want PDO connection
$conn=Database::getDB();
Use ceejayoz' proposal or add a global function which is responsible for establishing the database connection. The function is written as to connect to the database at most 1 time per HTTP request:
function getPDOConnection() {
// Thanks to the static-specifier, this variable will be initialized only once.
static $conn = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
return $conn;
}
This enables you to maintain the same connection in your whole application (but of course you don't have to use the function everywhere). Basically, this is a very simple application of the Singleton pattern. See the documentation of the static specifier/keyword and try to get familiar with the Singleton pattern.
Add your database connection as a parameter in the constructor, So you when you create a new instance from the user class it automatically runs across the instantiated object
The variable $DBH needs to be a member variable of your class.
Below private $password;, add private $DBH; and you're good to go with deleting the new-connection code from your login function.

Categories