2

at the moment I am using Database connections in classes like this:

public function __construct($db){
    $this->db = $db;
}

If I need it in another method I use it like this:

public function getElementbyID() {
    $stmt = $this->db->prepare("SELECT ...

But how do I use it in static methods? I am not able to use $this->db

public static function getElementbyID() {
    $stmt =    $this->db    ->prepare("SELECT ...

How can I use SomeClass::getElementFromDB() but in the function still use the Database Connection which I got in the __construct?

I don't want to use it like this: SomeClass::getElementFromDB($db) and I don't want to create a new Database Connection, because I already have one in $db.

Or - generally - how is this done?

Thank you!

3 Answers 3

3

There seems to be two main concerns that lead people to wrap PDO code in classes.

The first is a need to call the database once and reuse the database connection. For instance, you don't want to call the database inside each Model function as it will generate too many database connections, often more connections than your database server will allow.

The next is to prevent having to pass the database connection variable (e.g., $conn) to functions. This can be illustrated by example as the code ´select($table,$where)´ is preferred over ´select($conn,$table,$where)´.

There are several micro-frameworks / classes / libraries that does this for you. Some of the better include:

Or - generally - how is this done?

Personally I have come to prefer using procedural code (with a global $dbh variable to hold the database connection) that use "almost" plain PDO calls.

To do this, I first build a db() function to hold the database connection:

function db($dsn=null)
{
    global $dbh;
    if( isset($dbh) ) {
        return $dbh;
    } else {
        $dbh = new PDO($dsn);
        $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
        $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $dbh;
    }
}

Usage:

db("sqlite:articles.db");

$stmt = db()->prepare("INSERT INTO `article` (`id`,`title`,`body`) VALUES (:id, :title, :body)");
$stmt->execute([ ':id'=>$id, ':title'=>$title, ':body'=>$body ]);

Or:

$stmt = db()->prepare("SELECT * FROM `article` WHERE `id`=:id");
$stmt->execute([':id'=>542]);
$row = $stmt->fetch(PDO::FETCH_OBJ);
echo $row->id;
...

It even works within functions allowing me to create my own Model functions using a simple syntax:

db("sqlite:articles.db");

print_r( select_article("542") );

function select_article($id) {
    // Note that we use db() inside the function, without adding a $conn variable
    $stmt = db()->prepare("SELECT * FROM `article` WHERE `id`=:id AND published=1");
    $stmt->execute([':id'=>$id]);
    return $stmt->fetch(PDO::FETCH_ASSOC);
}

function insert($table,$data) {
    ...
    $stmt = db()->prepare("INSERT INTO `article` (`id`,`title`,`body`) VALUES (:id, :title, :body)");
    $stmt->execute([ ':id'=>$id, ':title'=>$title, ':body'=>$body ]);
}
Sign up to request clarification or add additional context in comments.

2 Comments

I am a bit unhappy to use the $dbh in global space. Do I have to care about this so much? Thank you for your answer!
The main risk is access control (any code can use the global variable). To make it less likely that the varname interfere with other code, you can rename $dbh to a unique var name $dbh983252. Global vars are required to share the database object between functions. You will find a discussion of global var pros and cons in this question: Replacing the global variables, how and why.
1

If you want to use a class in static way then you have to reconstruct all the properties and methods of that class to static. This is a class template your class should be, imho:

class Element
{
    protected static $db;

    public static function setConnection(PDO $pdo)
    {
        self::$db = $pdo;
    }

    public static function getElementByID($id)
    {
        // use self::$db to retrieve information
    }
}

// then you can use it directly without instantiate an instance
$element = Element::getElementByID($id);

Base on what you want to implicitly or explicitly call setConnection() to inject a database connection. You can use it explicitly like:

Element::setConnection($pdo);
$element = Element::getElementByID($id)

Or hiding all the setup by calling it implicitly (you may want to make use of singleton pattern in this by setting up a singleton Database class to provide Pdo instance to every class)

class Database
{
    protected static $db;

    private function __construct(){};

    public static function getPdo()
    {
        if (!$db) self::$db = new Pdo();
        return self::$db;
    }
}

class Element
{
    public static function getElementByID($id)
    {
        // all the code like above

        // call setConnection implicitly
        self::setConnection(Database::getPdo());
        // use self::$db to retrieve information
    }
}
// and just simply use
$element = Element::getElementByID($id);

you can also use Database::getPdo() every time a class need a connection, so the only one connection can be reused many time.

Regards,

2 Comments

Thank you for your answer. As I see this, so I am not able to use the Database Connection I already have and have to use it again for this class and any other static class, too?
If you already have a database connection and want to reuse it, then you have to inject it to that class somewhere, you can do it implicitly or explicitly. I have update the answer to reflect this. Regards,
0

I have coded a simple class you can add functions to that and you can also make it better and more efficient .

<?php
class Database
    {
        private $conn;
        private $handle;

        public static function __construct()
        {
        $dbhost = "localhost";
        $dbname = "pdo_test";
        $dbuser = "root";
        $dbpass = "";
        $charset = "utf8";

        /**
        * -database driver, host, db ( schema ) name and charset, as well as less frequently used port and unix_socket are going to DSN
        * -username and passwword are going to constructor
        * -al other options go to options array
        */

        $dsn = "mysql:host=$dbhost;dbname=$dbname;charset=$charset"; // DSN is a semicolon-delimited string consist of param = vale pairs.( DSN = Data Source Name )
        try
        {
            $this->conn = new PDO( $dsn, $dbuser, $dbpass, $opt );
            //echo "Database connection successful.<br />";
        }
        catch(PDOException $e)
        {
            echo "Error in database connection !!!<br />";
            echo $e->getMessage();
        }
        }

        public static function test($test)
        {
            echo "<br />".$test;
        }

        public  static function __destruct()
        {
            $this->conn = null;
            if(!$this->conn)
            {
        //  echo "<br />database disconnected !!";
            }
        }
    }

    Database::test("your query or table name and  condition according to your functions");

1 Comment

Thank you for your answer, but that was not what I asked! I already have a Database Class, it's only to connect to a static class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.