How to create 2 PDO database connection instances PHP - 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;
}
}

Related

Properly pass connection to connstructor PDO

I have spent several days reading different tutorials posts etc either info is outdated or appreciated.
I have a database connection class very simple
namespace App\Database;
use PDO;
use PDOException;
/**
* #desc Connection to the database
**/
class Database
{
protected string $dbhost = DATABASE_HOST;
protected string $dbuser = DATABASE_USER;
protected string $dbpass = DATABASE_PASS;
protected string $dbname = DATABASE_NAME;
protected PDO $conn;
public function __construct()
{
// Set DSN
$dsn = 'mysql:host=' . $this->dbhost . ';dbname=' . $this->dbname . ';charset=' . $this->charset;
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
// Create PDO instance
try {
$this->conn = new PDO($dsn, $this->dbuser, $this->dbpass, $options);
} catch (PDOException $e) {
echo 'Unable to establish a database connection: ' . $e->getMessage();
exit();
}
}
}
and in my user class I passed it to the constructor
protected Database $conn;
public function __construct()
{
$this->conn = new Database;
}
but when i write a statement like this
$stmt = $this->conn->prepare($sql);
prepare is high lighted saying Method 'prepare' not found in \App\Database\Database
I would prefer not to use static or singleton
Your variable $conn would probably better be named $db:
protected Database $db;
public function __construct()
{
$this->db = new Database;
}
Then, when you understand that the User class has a property called db which in turn has a property called conn, the proper use might make more sense:
$stmt = $this->db->conn->prepare($sql);
However, you've defined $conn as protected, so you can't do that. You could make it public, or make a getter method in Database:
public function getConn(): PDO
{
return $this->conn;
}
And then do:
$stmt = $this->db->getConn()->prepare($sql);
Better, I'd forget all that and instead have Database extend PDO, then just override the constructor to configure with your custom values:
class Database extends PDO
{
public function __construct()
{
$dsn = sprintf(
'mysql:host=%s;dbname=%s;charset=%s',
DATABASE_HOST,
DATABASE_NAME,
DATABASE_CHARSET
);
parent::__construct(
$dsn,
DATABASE_USER,
DATABASE_PASS,
[
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]
);
}
}
Now you have a PDO-compatible database object that is pre-configured, and you can just use it like a regular PDO object:
class User
{
protected Database $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function whatever()
{
$this->db->prepare($sql);
// ...
}
}
$db = new Database();
$user = new User($db);
$user->whatever();

How to call a local property using OOP?

I'm a beginner looking to learn more about PHP OOP, so there are things I don't know, in the ShowUsers() method, I would like to display all users in the database, but I'm not getting it, because I don't know how to call the connection property. If I've been using encapsulation, it would be easy, but I'm using the connection property as local, and I really don't know how to call this property, how can I call it without using encapsulation?
db.php
<?php
class DbConnect {
private $host = 'localhost';
private $dbname = 'database';
private $username = 'root';
private $password = '';
public function __construct() {
try {
$conn = new PDO("mysql:host=$this->host;dbname=$this->dbname", $this->username, $this->password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $exception) {
throw new Exception($exception->getMessage());
}
}
}
main.php
<?php
require_once 'db.php';
class Main extends DbConnect {
public function __construct() {
parent::__construct();
}
public function ShowUsers() {
$sql = "SELECT * FROM users";
$result = parent::__construct()->prepare($sql); //Problem here
$result->execute();
}
}
$object = new Main();
$object->ShowUsers();
Note: I don't want to use encapsulation to make it work, I want to learn how to call the variable without using encapsulation, if possible.
Based on the code above and the comments, I recommend that you declare $conn as protected in your DbConnect class:
<?php
// db.php
class DbConnect {
private $host = 'localhost';
private $dbname = 'database';
private $username = 'root';
private $password = '';
protected $conn;
public function __construct() {
try {
$this->conn = new PDO("mysql:host=$this->host;dbname=$this->dbname", $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $exception) {
throw new Exception($exception->getMessage());
}
}
}
Then in main.php, you can do:
<?php
// main.php
require_once 'db.php';
class Main extends DbConnect {
public function __construct() {
parent::__construct();
}
public function ShowUsers() {
$sql = "SELECT * FROM users";
$result = $this->conn->prepare($sql);
$result->execute();
}
}
$object = new Main();
$object->ShowUsers();
?>

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.

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 - PDO Connection Class - Unable To Access

I'm currently writing my first PHP application using OOP and PDO. In doing so I'm working on a connection class so that I can initiate a database connection when needed. I believe the terms for the way I am doing it is dependency injection.
I currently have an error when trying to access the connection.
This is my connection class:
class db{
private $host = '';
private $dbname = '';
private $username = '';
private $password ='';
public $con = '';
function __construct(){
$this->connect();
}
function connect(){
try{
$this->con = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username, $this->password);
$this->con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
echo 'We have a problem!';
}
}
}
And this is how I am trying to call it inside of other classes.
private $con;
public function __construct(db $con) {
$this->con = $con;
}
However this is the error I receive when trying to run it.
Catchable fatal error: Argument 1 passed to users::__construct() must be an instance of db, none given.
Any advice on what I am doing incorrectly would be much appreciated.
You will need to first create your DB instance and pass it to the constructor of your 'Other' class
$db = new DB();
$class = new OtherClass($db);
Apart from that, there are other issues:
The DB class constructor did not assign values to the database name, user and password etc. One way of doing it is to pass those settings to the constructor of DB and assign the values to the private properties.
class DB{
private $host = '';
private $dbname = '';
private $username = '';
private $password ='';
public $con = '';
function __construct($host, $dbname, $username, $password){
$this->host = $host;
$this->dbname = $dbname;
$this->username = $username;
$this->password = $password;
$this->connect();
}
function connect(){
try{
$this->con = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username, $this->password);
$this->con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
echo 'We have a problem!';
}
}
}

Categories