Return database connection from function - php

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.

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

PHP Out of class pdo connection fails

I can not make the PDO connection outside the class. Browser gives 500 error. I want to write PDO codes in out class. I am doing global change, but it is not.
try {
$pas = new PDO('mysql:host=localhost; dbname=tets', 'root', '123');
$pas->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$pas->exec("SET CHARACTER SET utf8"); // return all sql requests as UTF-8
} catch (Exception $e) {
echo $e->getMessage();
}
/**
User Avatar Check
**/
class Usercheck
{
public $sql , $paso;
public function __construct()
{
global $pas;
$this->paso =& $pas;
}
public function smf_members($whatid)
{
$this->sql = $this->paso->query("SELECT * FROM smf_members WHERE id_member = $whatid");
}
public function fetchcheck(){
if ($this->sql) {
return $this->sql->fetch(PDO::FETCH_BOTH);
}
}
}
$memberuser = new Usercheck();
$memberuser->smf_members('1');
It is not a good practice to use $global. There are many solutions to achieve what you want to do, and here is my approach.
1) Create a Connection Class to handle the PDO connectivity.
use PDO;
/**
* PDO Connection Classes
* Used by Database wrapper class to ensure that there is only one connection
*/
class Connection
{
private $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME. ';charset=' . DB_CHARSET;
private $conn;
private $error;
public function __construct()
{
try
{
$this->conn = new PDO($this->dsn, DB_USER, DB_PASSWORD);
}
catch(PDOException $e)
{
$this->error = $e->getMessage();
}
}
public function getConnection()
{
return $this->conn;
}
}
2) Establish the PDO connection via your wrapper class __construct(), the __construct() also ensure that there is only one PDO connection is instantiated.
use PDO;
class UserCheck
{
private $conn;
private $db;
public function __construct()
{
if (!$this->db) {
$conn = new Connection();
$this->db = $conn->getConnection();
}
}
}
I'm highly recommend that you read this PDO tutorial on how to use PDO and many best practice tips.

How to use database connection in other classes

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

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 - multiple different databases dependency injected class

I've spent the last several hours trying to find an answer to the "best", most logical, etc way to write a php database class to simultaneously connect to one postgresql db and one mysql db. Also, I'd like to adopt a Dependency Injection design but am new to that whole concept.
So far I've come up with...
class Database {
public function PgSqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$pgsql_dbh = new PDO("pgsql:host=$host; dbname=$dbname", $user, $pass);
$pgsql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$pgsql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $pgsql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
public function MySqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$mysql_dbh = new PDO("mysql:host=$host; dbname=$dbname", $user, $pass);
$mysql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$mysql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $mysql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
}
Obviously the duplicated code violates the DRY approach. I know and have seen many examples of multiple db connections, but most deal with same driver and don't provide DI capability.
I should also add that I've considered placing the connection details into the Database class constructor as...
$driver = 'mysql';
...
$mysqldb = new Database($driver,$un,$pw,...);
$driver = 'pgsql';
...
$pgsqldb = new Database($driver,$un,$pw,...);
but I don't know if that is really a good idea nor how well it would work with DI.
Many thanks!
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);
To avoid duplicated code you can extend an abstract class
abstract class AbstractDb {
public function connect() {
// common code to avoid duplication
echo 'connected!';
}
abstract public function escapeField();
abstract public function escapeValue();
}
class MySQL extends AbstractDb {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
$db = new MySQL;
$db->connect();
Or use composition, and let the Db class use a different driver for db-specific methods
interface IDriver {
public function escapeField();
public function escapeValue();
}
class MySQLDriver implements IDriver {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
class Db {
public function __construct($driver) {
$this->driver = $driver;
}
public function connect() {
// common code here ? idk, it's just an example
echo 'connect!';
}
// this method is db-specific, so we call the driver
public function escapeField($field) {
return $this->driver->escapeField($field);
}
public function escapeValue() {
// same here
}
}
$db = new Db(new MySQLDriver);
$db->connect();
In php 5.4 there will be traits, so there will be more approaches to avoid code duplication.

Categories